| #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 |