blob: fe61971b852cfa433fafc4b94af65d008f2f397d [file]
#include <array>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <ios>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/cleanup/cleanup.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "boost/system/detail/error_code.hpp" // NOLINT
#include "http_request.hpp"
#include "logging.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
#include "subprocess_utils.hpp"
#include "subprocess_utils_fake.hpp"
#include "systems.hpp"
#include "test/redfish-core/lib/snapshot_fixture.hpp"
#include <nlohmann/json.hpp>
#include "tlbmc/hal/system_registry_mock.h"
#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 ::dbus::utility::DbusVariantType;
using ::managedStore::KeyType;
using ::managedStore::ManagedType;
using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeAction;
using ::managedStore::SimulateSuccessfulAsyncPostDbusCallThreadSafeAction;
using ::managedStore::ValueType;
using ::milotic_tlbmc::MockSystemRegistry;
using ::testing::_;
using ::testing::An;
TEST(HandlerSystemTest, VerifyCreateResetActionInfoResponse) {
auto shareAsyncResp = std::make_shared<bmcweb::AsyncResp>();
createResetActionInfoResponse(shareAsyncResp, "test");
nlohmann::json& json = shareAsyncResp->res.jsonValue;
EXPECT_EQ(json["@odata.id"], "/redfish/v1/Systems/test/ResetActionInfo");
EXPECT_EQ(json["@odata.type"], "#ActionInfo.v1_1_2.ActionInfo");
EXPECT_EQ(json["Name"], "Reset Action Info");
EXPECT_EQ(json["Id"], "ResetActionInfo");
nlohmann::json::array_t parameters;
nlohmann::json::object_t parameter;
parameter["Name"] = "ResetType";
parameter["Required"] = true;
parameter["DataType"] = "String";
parameter["Delay"] = "Number";
nlohmann::json::array_t allowableValues;
allowableValues.emplace_back("On");
allowableValues.emplace_back("ForceOff");
allowableValues.emplace_back("ForceOn");
allowableValues.emplace_back("ForceRestart");
allowableValues.emplace_back("GracefulRestart");
allowableValues.emplace_back("GracefulShutdown");
allowableValues.emplace_back("PowerCycle");
allowableValues.emplace_back("Nmi");
#ifdef BMCWEB_ENABLE_REALLY_GRACEFUL_SHUTDOWN
allowableValues.emplace_back("ReallyGracefulShutDownTechDebt");
#endif
parameter["AllowableValues"] = std::move(allowableValues);
parameters.emplace_back(std::move(parameter));
nlohmann::json::object_t delayParameter;
delayParameter["Name"] = "Delay";
delayParameter["Required"] = false;
delayParameter["DataType"] = "Number";
parameters.emplace_back(std::move(delayParameter));
EXPECT_EQ(json["Parameters"], parameters);
}
TEST(GetSystemResetCommandFromInputTest, TestOnAndForceOnReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("On");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.On");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
SystemResetCommand systemResetCommandForceOn =
GetSystemResetCommandFromInput("ForceOn");
EXPECT_EQ(systemResetCommandForceOn.command,
"xyz.openbmc_project.State.Host.Transition.On");
EXPECT_TRUE(systemResetCommandForceOn.hostCommand);
EXPECT_TRUE(systemResetCommandForceOn.validCommand);
}
TEST(GetSystemResetCommandFromInputTest, TestForceOffReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("ForceOff");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Chassis.Transition.Off");
EXPECT_FALSE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
TEST(GetSystemResetCommandFromInputTest, TestForceRestartReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("ForceRestart");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.ForceWarmReboot");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
TEST(GetSystemResetCommandFromInputTest, TestGracefulShutdownReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("GracefulShutdown");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.Off");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
TEST(GetSystemResetCommandFromInputTest, TestGracefulRestartReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("GracefulRestart");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
TEST(GetSystemResetCommandFromInputTest, TestPowerCycleReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("PowerCycle");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.Reboot");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
#ifdef BMCWEB_ENABLE_REALLY_GRACEFUL_SHUTDOWN
TEST(GetSystemResetCommandFromInputTest,
TestReallyGracefulShutDownTechDebtReturnCorrectly) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("ReallyGracefulShutDownTechDebt");
EXPECT_EQ(systemResetCommandOn.command,
"xyz.openbmc_project.State.Host.Transition.ReallyGracefulShutDown");
EXPECT_TRUE(systemResetCommandOn.hostCommand);
EXPECT_TRUE(systemResetCommandOn.validCommand);
}
#endif
TEST(GetSystemResetCommandFromInputTest, TestInvalidInput) {
SystemResetCommand systemResetCommandOn =
GetSystemResetCommandFromInput("SomeInvalidInput");
EXPECT_FALSE(systemResetCommandOn.validCommand);
}
TEST(GetSystemSuffixHelperTest, TestAllInputs) {
// Empty, invalid strings
EXPECT_EQ("", getSystemSuffix(""));
EXPECT_EQ("", getSystemSuffix("asdf"));
EXPECT_EQ("", getSystemSuffix("syste"));
// Valid Systems/
EXPECT_EQ("", getSystemSuffix("system"));
EXPECT_EQ("1", getSystemSuffix("system1"));
EXPECT_EQ("13", getSystemSuffix("system13"));
EXPECT_EQ("FUTURE", getSystemSuffix("systemFUTURE"));
}
TEST(HandlerSystemTest, HelpersValuesEnable) {
auto shareAsyncResp = std::make_shared<bmcweb::AsyncResp>();
nlohmann::json& json = shareAsyncResp->res.jsonValue;
json["MemorySummary"]["Status"]["State"] = "Disabled";
json["ProcessorSummary"]["Count"] = 1;
json["ProcessorSummary"]["Status"]["State"] = "Disabled";
updateDimmProperties(shareAsyncResp, true);
modifyCpuPresenceState(shareAsyncResp, true);
modifyCpuFunctionalState(shareAsyncResp, true);
EXPECT_EQ(json["MemorySummary"]["Status"]["State"], "Enabled");
EXPECT_EQ(json["ProcessorSummary"]["Count"], 2);
EXPECT_EQ(json["ProcessorSummary"]["Status"]["State"], "Enabled");
}
class SystemResetSnapshotFixture : public SnapshotFixture {
protected:
static void SetupDbusMockIfNeeded() {
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
managedStore::KeyType systemKey(
managedStore::ManagedType::kManagedSubtreePaths, "/", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockSystems = {
"/xyz/openbmc_project/inventory/system1"};
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
systemKey, managedStore::MockManagedStoreTest::CreateValueType(
mockSystems))
.ok());
managedStore::KeyType hostAssocKey(
managedStore::ManagedType::kManagedAssociatedSubtree,
"/xyz/openbmc_project/inventory/system1/host_power",
"/xyz/openbmc_project/state", 0, {"xyz.openbmc_project.State.Host"});
dbus::utility::MapperGetSubTreeResponse mockHostAssoc = {
{ "/xyz/openbmc_project/state/host0",
{
{ "xyz.openbmc_project.State.Host",
{"xyz.openbmc_project.State.Host"} }
} }};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
hostAssocKey,
managedStore::MockManagedStoreTest::CreateValueType(
mockHostAssoc))
.ok());
managedStore::KeyType chassisAssocKey(
managedStore::ManagedType::kManagedAssociatedSubtree,
"/xyz/openbmc_project/inventory/system1/chassis_power",
"/xyz/openbmc_project/state", 0, {"xyz.openbmc_project.State.Chassis"});
dbus::utility::MapperGetSubTreeResponse mockChassisAssoc = {
{ "/xyz/openbmc_project/state/chassis0",
{
{ "xyz.openbmc_project.State.Chassis",
{"xyz.openbmc_project.State.Chassis"} }
} }};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
chassisAssocKey,
managedStore::MockManagedStoreTest::CreateValueType(
mockChassisAssoc))
.ok());
#endif
}
static std::string GetTestSystemName() {
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
return "system1";
#else
return "system";
#endif
}
};
TEST_F(SystemResetSnapshotFixture, PostSystemResetAsNMIOnDBusCallFailed) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.Control.Host.NMI",
"/xyz/openbmc_project/control/host0/nmi",
"xyz.openbmc_project.Control.Host.NMI", "NMI"))
.Times(1)
.WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeAction::
SimulateFailedAsyncPostDbusCall());
handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"Nmi\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(SystemResetSnapshotFixture, PostSystemResetAsNMIOnDBusCallSuccess) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.Control.Host.NMI",
"/xyz/openbmc_project/control/host0/nmi",
"xyz.openbmc_project.Control.Host.NMI", "NMI"))
.Times(1)
.WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeAction::
SimulateSuccessfulAsyncPostDbusCall());
handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"Nmi\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SystemResetSnapshotFixture, PostSystemResetSingleSystemHostResetOnFail) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
"org.freedesktop.DBus.Properties", "Set",
"xyz.openbmc_project.State.Host", "RequestedHostTransition",
dbus::utility::DbusVariantType(
"xyz.openbmc_project.State.Host.Transition.On")))
.Times(1)
.WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeAction::
SimulateFailedAsyncPostDbusCall());
handlePostComputerSystemReset(app_,
CreateRequest("{\"ResetType\":\"ForceOn\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemHostResetOnSuccess) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
"org.freedesktop.DBus.Properties", "Set",
"xyz.openbmc_project.State.Host", "RequestedHostTransition",
dbus::utility::DbusVariantType(
"xyz.openbmc_project.State.Host.Transition.On")))
.Times(1)
.WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeAction::
SimulateSuccessfulAsyncPostDbusCall());
handlePostComputerSystemReset(app_,
CreateRequest("{\"ResetType\":\"ForceOn\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemChassisResetOnFail) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.State.Chassis",
"/xyz/openbmc_project/state/chassis0",
"org.freedesktop.DBus.Properties", "Set",
"xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
dbus::utility::DbusVariantType(
"xyz.openbmc_project.State.Chassis.Transition.Off")))
.Times(1)
.WillOnce(SimulateFailedAsyncPostDbusCallThreadSafeAction::
SimulateFailedAsyncPostDbusCall());
handlePostComputerSystemReset(app_,
CreateRequest("{\"ResetType\":\"ForceOff\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemChassisResetOnSuccess) {
SetupDbusMockIfNeeded();
EXPECT_CALL(
*dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore()),
PostDbusCallToIoContextThreadSafe(
_, An<absl::AnyInvocable<void(const boost::system::error_code&)>&&>(),
"xyz.openbmc_project.State.Chassis",
"/xyz/openbmc_project/state/chassis0",
"org.freedesktop.DBus.Properties", "Set",
"xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
dbus::utility::DbusVariantType(
"xyz.openbmc_project.State.Chassis.Transition.Off")))
.Times(1)
.WillOnce(SimulateSuccessfulAsyncPostDbusCallThreadSafeAction::
SimulateSuccessfulAsyncPostDbusCall());
handlePostComputerSystemReset(app_,
CreateRequest("{\"ResetType\":\"ForceOff\"}"),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SnapshotFixture, CheckComputerSystemHostStateSingleHost) {
KeyType key(
ManagedType::kManagedProperty, "xyz.openbmc_project.State.Host",
sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"),
"xyz.openbmc_project.State.Host", "CurrentHostState");
const std::array<std::tuple<std::string, std::string, std::string>, 6>
testCases{
{{"xyz.openbmc_project.State.Host.HostState.Running", "On",
"Enabled"},
{"xyz.openbmc_project.State.Host.HostState.Quiesced", "On",
"Quiesced"},
{"xyz.openbmc_project.State.Host.HostState.DiagnosticMode", "On",
"InTest"},
{"xyz.openbmc_project.State.Host.HostState.TransitioningToRunning",
"PoweringOn", "Starting"},
{"xyz.openbmc_project.State.Host.HostState.TransitioningToOff",
"PoweringOff", "Disabled"},
{"xyz.openbmc_project.State.Host.HostState.OtherDummy", "Off",
"Disabled"}}};
for (auto testCase : testCases) {
const auto [currentHostState, powerState, status] = testCase;
DbusVariantType targetState = currentHostState;
std::shared_ptr<ValueType> mockHostStateValue =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(targetState));
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(key, mockHostStateValue)
.ok());
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_TRUE(json.contains("PowerState"));
EXPECT_TRUE(json.contains("Status"));
EXPECT_EQ(json["PowerState"], powerState);
EXPECT_TRUE(json["Status"].contains("State"));
EXPECT_EQ(json["Status"]["State"], status);
}
}
TEST_F(SnapshotFixture, GetSystemHostPowerAssociatedSubTreeFailed) {
// Looking for
// kManagedAssociatedSubtree|/xyz/openbmc_project/state|0|xyz.openbmc_project.State.Host|/host_power
KeyType key(ManagedType::kManagedAssociatedSubtree, "/host_power",
"/xyz/openbmc_project/state", 0,
{"xyz.openbmc_project.State.Host"});
absl::StatusOr<std::shared_ptr<ValueType>> associatedSubtreeObjectsStatusOr =
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->getMockObjectFromManagedStore(key);
ASSERT_TRUE(associatedSubtreeObjectsStatusOr.ok());
// TODO(b/416746677): Uncomment after the bug is fixed
// ASSERT_EQ(associatedSubtreeObjectsStatusOr.value()->managedType,
// ManagedType::kManagedSubtreePaths);
std::optional<dbus::utility::MapperGetSubTreeResponse>
originalAssociatedSubtree =
associatedSubtreeObjectsStatusOr.value()->managedSubtree;
ASSERT_TRUE(originalAssociatedSubtree.has_value());
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateErrorValueType(
originalAssociatedSubtree.value(),
boost::system::errc::make_error_code(
boost::system::errc::io_error)))
.ok());
absl::Cleanup mockManagedStoreResetter = [key, originalAssociatedSubtree]() {
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
originalAssociatedSubtree.value()))
.ok());
};
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
std::shared_ptr<ValueType> CreateMockAssociatedSubtree() {
dbus::utility::MapperGetSubTreeResponse mockAssociatedSubtree = {
std::make_pair(
"/xyz/openbmc_project/state/host1",
dbus::utility::MapperServiceMap{
{std::make_pair("xyz.openbmc_project.Chassis.Buttons1",
std::vector<std::string>{
"org.freedesktop.DBus.Introspectable",
"org.freedesktop.DBus.Peer",
"org.freedesktop.DBus.Properties",
"xyz.openbmc_project.State.Host",
}),
std::make_pair("xyz.openbmc_project.Control.Host.RestartCause1",
std::vector<std::string>{
"org.freedesktop.DBus.Introspectable",
"org.freedesktop.DBus.Peer",
"org.freedesktop.DBus.Properties",
"xyz.openbmc_project.State.Host",
})}}),
std::make_pair(
"/xyz/openbmc_project/state/host2",
dbus::utility::MapperServiceMap{
{std::make_pair("xyz.openbmc_project.Chassis.Buttons1",
std::vector<std::string>{
"org.freedesktop.DBus.Introspectable",
"org.freedesktop.DBus.Peer",
"org.freedesktop.DBus.Properties",
"xyz.openbmc_project.State.Host",
}),
std::make_pair("xyz.openbmc_project.Control.Host.RestartCause1",
std::vector<std::string>{
"org.freedesktop.DBus.Introspectable",
"org.freedesktop.DBus.Peer",
"org.freedesktop.DBus.Properties",
"xyz.openbmc_project.State.Host",
})}}),
};
return managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockAssociatedSubtree));
}
TEST_F(SnapshotFixture,
GetSystemHostPowerAssociatedSubTreeHasMoreThanOneObjects) {
crow::Logger::setLogLevel(crow::LogLevel::Error);
// Looking for
// kManagedAssociatedSubtree|/xyz/openbmc_project/state|0|xyz.openbmc_project.State.Host|/host_power
KeyType key(ManagedType::kManagedAssociatedSubtree, "/host_power",
"/xyz/openbmc_project/state", 0,
{"xyz.openbmc_project.State.Host"});
absl::StatusOr<std::shared_ptr<ValueType>> associatedSubtreeObjectsStatusOr =
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->getMockObjectFromManagedStore(key);
ASSERT_TRUE(associatedSubtreeObjectsStatusOr.ok());
// TODO(b/416746677): Uncomment after the bug is fixed
// ASSERT_EQ(associatedSubtreeObjectsStatusOr.value()->managedType,
// ManagedType::kManagedSubtreePaths);
std::optional<dbus::utility::MapperGetSubTreeResponse>
originalAssociatedSubtree =
associatedSubtreeObjectsStatusOr.value()->managedSubtree;
ASSERT_TRUE(originalAssociatedSubtree.has_value());
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(key, CreateMockAssociatedSubtree())
.ok());
absl::Cleanup mockManagedStoreResetter = [key, originalAssociatedSubtree]() {
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
originalAssociatedSubtree.value()))
.ok());
};
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(SnapshotFixture, GetSystemHostPowerAssociatedSubTreeHasEmptyObjects) {
KeyType key(ManagedType::kManagedAssociatedSubtree, "system1/host_power",
"/xyz/openbmc_project/state", 0,
{"xyz.openbmc_project.State.Host"});
dbus::utility::MapperGetSubTreeResponse mockAssociatedSubtree;
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockAssociatedSubtree)))
.ok());
KeyType chassis_key(ManagedType::kManagedAssociatedSubtree,
"system1/chassis_power", "/xyz/openbmc_project/state", 0,
{"xyz.openbmc_project.State.Chassis"});
dbus::utility::MapperGetSubTreeResponse mockChassisSubtree;
ASSERT_TRUE(
dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
chassis_key, managedStore::MockManagedStoreTest::CreateValueType(
std::move(mockChassisSubtree)))
.ok());
handleComputerSystem(share_async_resp_, "system1", "system1", true);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["PowerState"], "Unknown");
EXPECT_EQ(json["Status"]["State"], "Unknown");
EXPECT_EQ(json["LastResetTime"], "Unknown");
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemChassisResetOnSuccessDelay) {
SetupDbusMockIfNeeded();
SubprocessUtilsFake subprocessUtilsFake;
SubprocessUtilsBase::setInstance(
std::make_unique<SubprocessUtilsFake>(subprocessUtilsFake));
handlePostComputerSystemReset(
app_, CreateRequest("{\"ResetType\":\"ForceOff\", \"Delay\":1} "),
share_async_resp_, GetTestSystemName());
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 -- "
"curl -d {\"ResetType\":\"ForceOff\"} -H Content-Type: "
"application/json -X POST "
"localhost:80/redfish/v1/Systems/" +
GetTestSystemName() + "/Actions/ComputerSystem.Reset");
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemChassisResetOnFailTimeDelay) {
SetupDbusMockIfNeeded();
handlePostComputerSystemReset(
app_, CreateRequest("{\"ResetType\":\"ForceOff\", \"Delay\":901} "),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::bad_request);
}
TEST_F(SystemResetSnapshotFixture,
PostSystemResetSingleSystemChassisResetOnFailTypeDelay) {
SetupDbusMockIfNeeded();
handlePostComputerSystemReset(
app_, CreateRequest("{\"ResetType\":\"PleaseReset\", \"Delay\":1} "),
share_async_resp_, GetTestSystemName());
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::bad_request);
}
TEST_F(SnapshotFixture, HandleGetSystemBootGuestOSInfo) {
handleGetSystemBootGuestOSInfo(app_, CreateRequest(""), share_async_resp_,
"system2");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/System/system2/Oem/Google/BootGuestOSActionInfo");
}
TEST_F(SnapshotFixture, handleGetBareMetalInstanceBase) {
handleGetBareMetalInstance(app_, CreateRequest(""), share_async_resp_,
"system1");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system1/Oem/Google/BareMetalInstance");
EXPECT_EQ(json["@odata.type"],
"#GoogleBareMetalInstance.v1_0_0.GoogleBareMetalInstance");
}
TEST_F(SystemResetSnapshotFixture, HandleGetBootNumber) {
SetupDbusMockIfNeeded();
std::string biosPath =
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
"/xyz/openbmc_project/inventory/system1/chassis/motherboard/bios";
#else
"/xyz/openbmc_project/inventory/system/chassis/motherboard/bios";
#endif
KeyType key(ManagedType::kManagedProperty,
"xyz.openbmc_project.Smbios.MDR_V2",
sdbusplus::message::object_path(biosPath),
"xyz.openbmc_project.State.Host", "BootCount");
uint32_t num = 1000;
std::shared_ptr<ValueType> bootCountValue =
managedStore::MockManagedStoreTest::CreateValueType(std::move(num));
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(key, bootCountValue)
.ok());
handleGetBootNumber(app_, CreateRequest(""), share_async_resp_,
GetTestSystemName());
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"], "/redfish/v1/Systems/" + GetTestSystemName() +
"/Oem/Google/BootNumber");
EXPECT_EQ(json["@odata.type"], "#GoogleBootNumber.v1_0_0.GoogleBootNumber");
EXPECT_TRUE(json.contains("BootNumber"));
EXPECT_EQ(json["BootNumber"], 1000);
}
TEST_F(SnapshotFixture, SingleHostPlatformIncludesBios) {
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_TRUE(json.contains("Bios"));
EXPECT_EQ(json["Bios"]["@odata.id"], "/redfish/v1/Systems/system/Bios");
}
TEST(SystemsTest, SetAndGetBootOrder) {
const std::string biosSettingFile = "/tmp/oem_bios_setting.test";
// Ensure file is removed before and after test
std::remove(biosSettingFile.c_str());
auto cleanup =
absl::MakeCleanup([&]() { std::remove(biosSettingFile.c_str()); });
auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
// Test setting the boot order
std::vector<std::string> bootOrderToWrite = {"Boot0001", "Boot0000",
"Boot0028"};
setBootOrder(asyncResp, bootOrderToWrite, biosSettingFile);
// Verify the file content
std::ifstream fileIn(biosSettingFile, std::ios::binary);
ASSERT_TRUE(fileIn.is_open());
std::vector<uint16_t> bootIndices;
uint16_t index;
while (fileIn.read(reinterpret_cast<char*>(&index), sizeof(index))) {
bootIndices.push_back(index);
}
fileIn.close();
ASSERT_EQ(bootIndices.size(), 3);
EXPECT_EQ(bootIndices[0], 1);
EXPECT_EQ(bootIndices[1], 0);
EXPECT_EQ(bootIndices[2], 0x28);
// Test getting the boot order
asyncResp->res.clear();
getBootOrder(asyncResp, biosSettingFile);
EXPECT_EQ(asyncResp->res.jsonValue["Boot"]["BootOrder"], bootOrderToWrite);
}
TEST(SystemsTest, SetAndGetBootOrderHex) {
const std::string biosSettingFile = "/tmp/oem_bios_setting.test";
// Ensure file is removed before and after test
std::remove(biosSettingFile.c_str());
auto cleanup =
absl::MakeCleanup([&]() { std::remove(biosSettingFile.c_str()); });
auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
// Test setting the boot order
std::vector<std::string> bootOrderToWrite = {"Boot0001", "Boot0000",
"BootFFFE"};
setBootOrder(asyncResp, bootOrderToWrite, biosSettingFile);
// Verify the file content
std::ifstream fileIn(biosSettingFile, std::ios::binary);
ASSERT_TRUE(fileIn.is_open());
std::vector<uint16_t> bootIndices;
uint16_t index;
while (fileIn.read(reinterpret_cast<char*>(&index), sizeof(index))) {
bootIndices.push_back(index);
}
fileIn.close();
ASSERT_EQ(bootIndices.size(), 3);
EXPECT_EQ(bootIndices[0], 1);
EXPECT_EQ(bootIndices[1], 0);
EXPECT_EQ(bootIndices[2], 0xFFFE);
// Test getting the boot order
asyncResp->res.clear();
getBootOrder(asyncResp, biosSettingFile);
EXPECT_EQ(asyncResp->res.jsonValue["Boot"]["BootOrder"], bootOrderToWrite);
}
TEST(SystemsTest, SetBootOrderInvalidFormat) {
const std::string biosSettingFile = "/tmp/oem_bios_setting.test";
std::remove(biosSettingFile.c_str());
auto cleanup =
absl::MakeCleanup([&]() { std::remove(biosSettingFile.c_str()); });
auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
std::vector<std::string> bootOrderToWrite = {"InvalidBoot0001"};
setBootOrder(asyncResp, bootOrderToWrite, biosSettingFile);
// Expect an error message
EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::bad_request);
// File should not have been created or should be empty
std::ifstream fileIn(biosSettingFile, std::ios::binary | std::ios::ate);
EXPECT_TRUE(!fileIn.is_open() || fileIn.tellg() == 0);
}
TEST(SystemsTest, SetBootOrderIndexOutOfRange) {
const std::string biosSettingFile = "/tmp/oem_bios_setting.test";
std::remove(biosSettingFile.c_str());
auto cleanup =
absl::MakeCleanup([&]() { std::remove(biosSettingFile.c_str()); });
auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
std::vector<std::string> bootOrderToWrite = {"Boot99999"};
setBootOrder(asyncResp, bootOrderToWrite, biosSettingFile);
// Expect an error message
EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::bad_request);
// File should not have been created or should be empty
std::ifstream fileIn(biosSettingFile, std::ios::binary | std::ios::ate);
EXPECT_TRUE(!fileIn.is_open() || fileIn.tellg() == 0);
}
TEST(SystemsTest, SetBootOrderMixedCaseHex) {
const std::string biosSettingFile = "/tmp/oem_bios_setting.test";
// Ensure file is removed before and after test
std::remove(biosSettingFile.c_str());
auto cleanup =
absl::MakeCleanup([&]() { std::remove(biosSettingFile.c_str()); });
auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
// Test setting the boot order with mixed-case hex values
std::vector<std::string> bootOrderToWrite = {"Boot000f", "Boot0E40"};
setBootOrder(asyncResp, bootOrderToWrite, biosSettingFile);
// Verify the file content
std::ifstream fileIn(biosSettingFile, std::ios::binary);
ASSERT_TRUE(fileIn.is_open());
std::vector<uint16_t> bootIndices;
uint16_t index;
while (fileIn.read(reinterpret_cast<char*>(&index), sizeof(index))) {
bootIndices.push_back(index);
}
fileIn.close();
ASSERT_EQ(bootIndices.size(), 2);
EXPECT_EQ(bootIndices[0], 0x000f);
EXPECT_EQ(bootIndices[1], 0x0e40);
// Test getting the boot order
asyncResp->res.clear();
getBootOrder(asyncResp, biosSettingFile);
// getBootOrder normalizes to uppercase hex
std::vector<std::string> expectedBootOrder = {"Boot000F", "Boot0E40"};
EXPECT_EQ(asyncResp->res.jsonValue["Boot"]["BootOrder"], expectedBootOrder);
}
TEST(SystemsTest, GetBiosSettingPath) {
absl::StatusOr<std::string> path1 = getBiosSettingPath("system");
ASSERT_TRUE(path1.ok());
EXPECT_EQ(*path1, "/var/google/oem_bios_setting");
absl::StatusOr<std::string> path2 = getBiosSettingPath("system1");
ASSERT_TRUE(path2.ok());
EXPECT_EQ(*path2, "/var/google/system1/oem_bios_setting");
absl::StatusOr<std::string> path3 = getBiosSettingPath("system2");
ASSERT_TRUE(path3.ok());
EXPECT_EQ(*path3, "/var/google/system2/oem_bios_setting");
absl::StatusOr<std::string> path4 = getBiosSettingPath("unknown_system");
ASSERT_FALSE(path4.ok());
EXPECT_EQ(path4.status().code(), absl::StatusCode::kInvalidArgument);
}
#ifdef ENABLE_REDFISH_CONFIGURE_IFS
TEST_F(SnapshotFixture, GetIfsPropertiesPresent) {
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, GetBase64EncodedIfsPattern("system1"))
.WillOnce(::testing::Return("SGVsbG8h"));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
handleComputerSystem(share_async_resp_, "system1", "system1", true);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["Actions"]["Oem"]["Google"]
["#GoogleComputerSystem.ResetCpuIfsPattern"]["target"],
"/redfish/v1/Systems/system1/Actions/Oem/"
"GoogleComputerSystem.ResetCpuIfsPattern");
EXPECT_EQ(json["Oem"]["Google"]["CpuIfsPatternBase64"], "SGVsbG8h");
}
TEST_F(SnapshotFixture, GetIfsPropertiesEmptyPattern) {
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, GetBase64EncodedIfsPattern("system1"))
.WillOnce(::testing::Return(""));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
handleComputerSystem(share_async_resp_, "system1", "system1", true);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["Oem"]["Google"]["CpuIfsPatternBase64"], "");
}
TEST_F(SnapshotFixture, GetIfsPropertiesErrorFallback) {
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, GetBase64EncodedIfsPattern("system1"))
.WillOnce(
::testing::Return(absl::InternalError("Simulated internal error")));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
handleComputerSystem(share_async_resp_, "system1", "system1", true);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
#else
TEST_F(SnapshotFixture, GetIfsPropertiesFlagOff) {
handleComputerSystem(share_async_resp_, "system1", "system1", true);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_FALSE(json.contains("Actions") && json["Actions"].contains("Oem") &&
json["Actions"]["Oem"].contains("Google") &&
json["Actions"]["Oem"]["Google"].contains(
"#GoogleComputerSystem.ResetCpuIfsPattern"));
EXPECT_FALSE(json.contains("Oem") && json["Oem"].contains("Google") &&
json["Oem"]["Google"].contains("CpuIfsPatternBase64"));
}
#endif
#ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM
TEST_F(SnapshotFixture, HandleGetSystemsCollectionSingleHostFallbackDisabled) {
managedStore::KeyType key(managedStore::ManagedType::kManagedSubtreePaths,
"/", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockSystems = {
"/xyz/openbmc_project/inventory/system1"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockSystems))
.ok());
handleGetSystemsCollection(app_, CreateRequest(""), share_async_resp_);
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["Members"].size(), 1);
EXPECT_EQ(json["Members"][0]["@odata.id"], "/redfish/v1/Systems/system1");
}
#endif
TEST_F(SnapshotFixture, GetBootNextPresent) {
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, GetBootNext("system"))
.WillOnce(::testing::Return("Boot0001"));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["Boot"]["BootNext"], "Boot0001");
}
TEST_F(SnapshotFixture, GetBootNextNotFound) {
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, GetBootNext("system"))
.WillOnce(::testing::Return(absl::NotFoundError("")));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
handleComputerSystem(share_async_resp_, "", "system", false);
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_FALSE(json["Boot"].contains("BootNext"));
}
TEST_F(SnapshotFixture, PatchBootNext) {
managedStore::KeyType key(managedStore::ManagedType::kManagedSubtreePaths,
"/", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockSystems = {
"/xyz/openbmc_project/inventory/system"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockSystems))
.ok());
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, SetBootNext("system", "Boot0002"))
.WillOnce(::testing::Return(absl::OkStatus()));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
crow::Request req = CreateRequest("{\"Boot\": {\"BootNext\": \"Boot0002\"}}");
req.req.method(boost::beast::http::verb::patch);
handlePatchComputerSystemCollection(app_, req, share_async_resp_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::no_content);
}
TEST_F(SnapshotFixture, PatchBootNextRegistryNull) {
managedStore::KeyType key(managedStore::ManagedType::kManagedSubtreePaths,
"/", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockSystems = {
"/xyz/openbmc_project/inventory/system"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockSystems))
.ok());
managedStore::GetManagedObjectStore()->SetSystemRegistry(nullptr);
crow::Request req = CreateRequest("{\"Boot\": {\"BootNext\": \"Boot0002\"}}");
req.req.method(boost::beast::http::verb::patch);
handlePatchComputerSystemCollection(app_, req, share_async_resp_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
TEST_F(SnapshotFixture, PatchBootNextSetFailed) {
managedStore::KeyType key(managedStore::ManagedType::kManagedSubtreePaths,
"/", 0,
{"xyz.openbmc_project.Inventory.Item.System"});
std::vector<std::string> mockSystems = {
"/xyz/openbmc_project/inventory/system"};
ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>(
managedStore::GetManagedObjectStore())
->upsertMockObjectIntoManagedStore(
key, managedStore::MockManagedStoreTest::CreateValueType(
mockSystems))
.ok());
auto mock_registry = std::make_shared<MockSystemRegistry>();
EXPECT_CALL(*mock_registry, SetBootNext("system", "Boot0002"))
.WillOnce(::testing::Return(
absl::InternalError("Simulated write failure")));
managedStore::GetManagedObjectStore()->SetSystemRegistry(mock_registry);
crow::Request req = CreateRequest("{\"Boot\": {\"BootNext\": \"Boot0002\"}}");
req.req.method(boost::beast::http::verb::patch);
handlePatchComputerSystemCollection(app_, req, share_async_resp_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),
boost::beast::http::status::internal_server_error);
}
} // namespace
} // namespace redfish