blob: ed209f353033cd8bab502bee2e0c94b735464708 [file] [log] [blame]
#include "absl/cleanup/cleanup.h"
#include "app.hpp"
#include "bmcweb_config.h"
#include "async_resp.hpp"
#include "http_response.hpp"
#include "nlohmann/json.hpp"
#include "systems.hpp"
#include "snapshot_fixture.hpp"
#include <memory>
#include <vector>
#include <gmock/gmock.h> // IWYU pragma: keep
#include <gtest/gtest.h> // IWYU pragma: keep
// IWYU pragma: no_include <gtest/gtest-message.h>
// IWYU pragma: no_include <gtest/gtest-test-part.h>
// IWYU pragma: no_include "gtest/gtest_pred_impl.h"
// IWYU pragma: no_include <gmock/gmock-matchers.h>
// IWYU pragma: no_include <gtest/gtest-matchers.h>
namespace redfish
{
namespace
{
using ::dbus::utility::DbusVariantType;
using ::managedStore::KeyType;
using ::managedStore::ManagedObjectStoreContext;
using ::managedStore::ManagedType;
using ::managedStore::SimulateFailedAsyncPostDbusCallThreadSafeAction;
using ::managedStore::SimulateSuccessfulAsyncPostDbusCallThreadSafeAction;
using ::managedStore::ValueType;
using ::testing::An;
using ::testing::_;
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");
allowableValues.emplace_back("ReallyGracefulShutDownTechDebt");
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);
}
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);
}
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");
}
TEST_F(SnapshotFixture, PostSystemResetAsNMIOnDBusCallFailed){
EXPECT_CALL(*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_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::internal_server_error);
}
TEST_F(SnapshotFixture, PostSystemResetAsNMIOnDBusCallSuccess){
EXPECT_CALL(*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_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemHostResetOnFail){
EXPECT_CALL(*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_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::internal_server_error);
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemHostResetOnSuccess){
EXPECT_CALL(*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_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok);
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemChassisResetOnFail){
EXPECT_CALL(*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_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::internal_server_error);
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemChassisResetOnSuccess){
EXPECT_CALL(*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_, "system");
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(
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 =
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(
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(
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 =
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(managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(
key, CreateMockAssociatedSubtree())
.ok());
absl::Cleanup mockManagedStoreResetter = [key,
originalAssociatedSubtree]() {
ASSERT_TRUE(
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, PostSystemResetSingleSystemChassisResetOnSuccessDelay){
handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"ForceOff\", \"Delay\":1} "), share_async_resp_, "system");
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/system/Actions/ComputerSystem.Reset");
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemChassisResetOnFailTimeDelay){
handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"ForceOff\", \"Delay\":901} "), share_async_resp_, "system");
RunIoUntilDone();
EXPECT_EQ(share_async_resp_->res.result(),boost::beast::http::status::bad_request);
}
TEST_F(SnapshotFixture, PostSystemResetSingleSystemChassisResetOnFailTypeDelay){
handlePostComputerSystemReset(app_, CreateRequest("{\"ResetType\":\"PleaseReset\", \"Delay\":1} "), share_async_resp_, "system");
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");
}
} // namespace
} // namespace redfish