| #include "system_utils.hpp" | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include <string_view> | |
| #include <vector> | |
| #include <gtest/gtest.h> | |
| #include "async_resp.hpp" | |
| #include "storage.hpp" | |
| #include "test/redfish-core/lib/snapshot_fixture.hpp" | |
| #include <nlohmann/json.hpp> // IWYU pragma: keep | |
| #include "managed_store.hpp" // IWYU pragma: keep | |
| #include "managed_store_types.hpp" // IWYU pragma: keep | |
| #include "test/g3/mock_managed_store.hpp" // IWYU pragma: keep | |
| #include "test/g3/mock_managed_store_test.hpp" // IWYU pragma: keep | |
| namespace redfish::system_utils { | |
| namespace { | |
| class SystemUtilsTest : public SnapshotFixture {}; | |
| TEST_F(SystemUtilsTest, IsHardcodedSingleHost) { | |
| #ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM | |
| EXPECT_FALSE(isHardcodedSingleHost(0)); | |
| EXPECT_FALSE(isHardcodedSingleHost(1)); | |
| EXPECT_FALSE(isHardcodedSingleHost(2)); | |
| #else | |
| EXPECT_TRUE(isHardcodedSingleHost(0)); | |
| EXPECT_TRUE(isHardcodedSingleHost(1)); | |
| EXPECT_FALSE(isHardcodedSingleHost(2)); | |
| EXPECT_FALSE(isHardcodedSingleHost(3)); | |
| #endif | |
| } | |
| void VerifyFindSystemPathAndTriggerCallback( | |
| const std::string& systemName, | |
| const std::vector<std::string>& objects, | |
| const boost::beast::http::status expectedStatus, | |
| const std::optional<std::string>& expectedPath) { | |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); | |
| bool callbackTriggered = false; | |
| std::string callbackPath; | |
| findSystemPathAndTriggerCallback( | |
| asyncResp, systemName, objects, | |
| [&callbackTriggered, &callbackPath]( | |
| const std::shared_ptr<bmcweb::AsyncResp>& /*resp*/, | |
| const std::string& path) { | |
| callbackTriggered = true; | |
| callbackPath = path; | |
| }); | |
| EXPECT_EQ(asyncResp->res.result(), expectedStatus); | |
| if (expectedPath.has_value()) { | |
| EXPECT_TRUE(callbackTriggered); | |
| EXPECT_EQ(callbackPath, *expectedPath); | |
| } else { | |
| EXPECT_FALSE(callbackTriggered); | |
| } | |
| } | |
| TEST_F(SystemUtilsTest, FindSystemPathAndTriggerCallback) { | |
| #ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM | |
| VerifyFindSystemPathAndTriggerCallback( | |
| "system1", | |
| {"/xyz/openbmc_project/inventory/system1"}, | |
| boost::beast::http::status::ok, "/xyz/openbmc_project/inventory/system1"); | |
| VerifyFindSystemPathAndTriggerCallback( | |
| "system", | |
| {"/xyz/openbmc_project/inventory/system1"}, | |
| boost::beast::http::status::not_found, std::nullopt); | |
| #else | |
| VerifyFindSystemPathAndTriggerCallback( | |
| "system", {"/xyz/openbmc_project/inventory/system1"}, | |
| boost::beast::http::status::ok, ""); | |
| VerifyFindSystemPathAndTriggerCallback( | |
| "wrongName", {"/xyz/openbmc_project/inventory/system1"}, | |
| boost::beast::http::status::not_found, std::nullopt); | |
| #endif | |
| VerifyFindSystemPathAndTriggerCallback( | |
| "system2", | |
| {"/xyz/openbmc_project/inventory/system1", | |
| "/xyz/openbmc_project/inventory/system2"}, | |
| boost::beast::http::status::ok, "/xyz/openbmc_project/inventory/system2"); | |
| } | |
| TEST_F(SystemUtilsTest, ParseSystemNameToIndex) { | |
| // Single host | |
| auto index = parseSystemNameToIndex("system", false); | |
| ASSERT_TRUE(index.ok()); | |
| EXPECT_EQ(*index, 0); | |
| #ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM | |
| // When fallback is disabled, system1 is parsed to index 0 via fall-through | |
| auto index1 = parseSystemNameToIndex("system1", false); | |
| ASSERT_TRUE(index1.ok()); | |
| EXPECT_EQ(*index1, 0); | |
| auto index2 = parseSystemNameToIndex("system2", false); | |
| ASSERT_TRUE(index2.ok()); | |
| EXPECT_EQ(*index2, 1); | |
| #else | |
| // When fallback is enabled, system1 is rejected for single host | |
| EXPECT_FALSE(parseSystemNameToIndex("system1", false).ok()); | |
| EXPECT_FALSE(parseSystemNameToIndex("system2", false).ok()); | |
| #endif | |
| // host0 is not supported as the service expects system prefix | |
| EXPECT_FALSE(parseSystemNameToIndex("host0", false).ok()); | |
| EXPECT_FALSE(parseSystemNameToIndex("system0", false).ok()); | |
| EXPECT_FALSE(parseSystemNameToIndex("wrongName", false).ok()); | |
| // Multiple hosts | |
| EXPECT_FALSE(parseSystemNameToIndex("system", true).ok()); | |
| EXPECT_FALSE(parseSystemNameToIndex("system0", true).ok()); | |
| EXPECT_FALSE(parseSystemNameToIndex("wrongName", true).ok()); | |
| EXPECT_TRUE(parseSystemNameToIndex("system1", true).ok()); | |
| EXPECT_EQ(parseSystemNameToIndex("system1", true).value_or(-1), 0); | |
| EXPECT_TRUE(parseSystemNameToIndex("system2", true).ok()); | |
| EXPECT_EQ(parseSystemNameToIndex("system2", true).value_or(-1), 1); | |
| } | |
| void VerifySystemStorageCollection( | |
| SnapshotFixture* fixture, const std::string& systemName, | |
| const std::optional<std::string>& storageObjectPath, | |
| const std::optional<std::string>& expectedMemberId) { | |
| if (storageObjectPath.has_value()) { | |
| managedStore::KeyType systemKey( | |
| managedStore::ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.System"}); | |
| std::vector<std::string> mockSystems = { | |
| "/xyz/openbmc_project/inventory/" + systemName}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| systemKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| mockSystems)) | |
| .ok()); | |
| managedStore::KeyType storageKey( | |
| managedStore::ManagedType::kManagedAssociatedSubtreePaths, | |
| "/xyz/openbmc_project/inventory/" + systemName + "/containing", | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.Storage"}); | |
| std::vector<std::string> mockStorage = {*storageObjectPath}; | |
| ASSERT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| storageKey, | |
| managedStore::MockManagedStoreTest::CreateValueType( | |
| mockStorage)) | |
| .ok()); | |
| } | |
| auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); | |
| handleGetSystemStorageCollection(asyncResp, systemName); | |
| fixture->RunIoUntilDone(); | |
| EXPECT_EQ(asyncResp->res.result(), boost::beast::http::status::ok); | |
| if (expectedMemberId.has_value()) { | |
| EXPECT_EQ(asyncResp->res.jsonValue["Members"].size(), 1); | |
| EXPECT_EQ(asyncResp->res.jsonValue["Members"][0]["@odata.id"], | |
| *expectedMemberId); | |
| } | |
| } | |
| TEST_F(SystemUtilsTest, HandleGetSystemStorageCollectionTest) { | |
| #ifdef BMCWEB_ALLOW_NON_HARDCODED_SINGLEHOST_SYSTEM | |
| VerifySystemStorageCollection( | |
| this, "system1", "/xyz/openbmc_project/inventory/system1/storage1", | |
| "/redfish/v1/Systems/system1/Storage/storage1"); | |
| #else | |
| VerifySystemStorageCollection(this, "system", std::nullopt, std::nullopt); | |
| #endif | |
| } | |
| } // namespace | |
| } // namespace redfish::system_utils |