blob: c7a395a49cc88c186bd5f6fa598b2381277d4eab [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 "dbus_utility.hpp"
#include <fstream>
#include <ios>
#include <memory>
#include <vector>
#include <string>
#include <sstream>
#include <iomanip>
#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");
}
TEST_F(SnapshotFixture, HandleGetBootNumber)
{
const std::string bootCountPath =
"/xyz/openbmc_project/inventory/system";
KeyType key(ManagedType::kManagedProperty,
"xyz.openbmc_project.Smbios.MDR_V2",
sdbusplus::message::object_path("/xyz/openbmc_project/inventory/system/chassis/motherboard/bios"),
"xyz.openbmc_project.State.Host", "BootCount");
uint32_t num = 1000;
std::shared_ptr<ValueType> bootCountValue =
managedStore::MockManagedStoreTest::CreateValueType(
std::move(num)
);
ASSERT_TRUE(
managedStore::GetManagedObjectStore()
->upsertMockObjectIntoManagedStore(
key, bootCountValue)
.ok());
handleGetBootNumber(app_, CreateRequest(""), share_async_resp_,
"system");
RunIoUntilDone();
nlohmann::json& json = share_async_resp_->res.jsonValue;
EXPECT_EQ(json["@odata.id"],
"/redfish/v1/Systems/system/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);
}
} // namespace
} // namespace redfish