| #include "processor.hpp" | |
| #include <filesystem> | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include <gtest/gtest.h> | |
| #include "async_resp.hpp" | |
| #include "dbus_utility.hpp" | |
| #include "query.hpp" | |
| #include "external_storer.hpp" | |
| #include "test/redfish-core/lib/snapshot_fixture.hpp" | |
| #include <nlohmann/json.hpp> | |
| #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::DBusInteracesMap; | |
| using ::dbus::utility::DBusPropertiesMap; | |
| using ::dbus::utility::DbusVariantType; | |
| using ::dbus::utility::MapperGetSubTreePathsResponse; | |
| using ::dbus::utility::MapperGetSubTreeResponse; | |
| using ::dbus::utility::MapperServiceMap; | |
| using ::managedStore::KeyType; | |
| using ::managedStore::ManagedType; | |
| using ::managedStore::ValueType; | |
| class ProcessorSnapshotFixture : public SnapshotFixture { | |
| protected: | |
| static void SetUpTestSuite() { | |
| SnapshotFixture::SetUpTestSuite(); | |
| const_cast<std::filesystem::path&>(external_storer::defPathPrefix) = | |
| "/tmp/bmcweb"; | |
| } | |
| }; | |
| TEST(ProcessorTest, IsValidSystemServicePair) { | |
| // Positive test cases | |
| EXPECT_TRUE(isValidSystemServicePair("system", "xyz.openbmc_project.pldm")); | |
| EXPECT_TRUE(isValidSystemServicePair("system1", "xyz.openbmc_project.pldm0")); | |
| EXPECT_TRUE(isValidSystemServicePair("system2", "xyz.openbmc_project.pldm1")); | |
| // Negative test cases | |
| EXPECT_FALSE( | |
| isValidSystemServicePair("system1", "xyz.openbmc_project.pldm1")); | |
| EXPECT_FALSE( | |
| isValidSystemServicePair("system3", "xyz.openbmc_project.pldm0")); | |
| EXPECT_FALSE( | |
| isValidSystemServicePair("system1", "xyz.openbmc_project.pldm.invalid")); | |
| EXPECT_FALSE(isValidSystemServicePair("", "xyz.openbmc_project.pldm0")); | |
| EXPECT_FALSE(isValidSystemServicePair("system1", "")); | |
| } | |
| MapperGetSubTreeResponse CreateMapperGetSubTreeResponse() { | |
| return MapperGetSubTreeResponse({std::make_pair( | |
| "/xyz/openbmc_project/pldm/4/effecter/power/SOC_TDP_4", | |
| MapperServiceMap({{"xyz.openbmc_project.pldm", | |
| { | |
| "xyz.openbmc_project.Effecter.Value", | |
| "xyz.openbmc_project.Effecter.SetNumericEffecter", | |
| "xyz.openbmc_project.State.Decorator.Availability", | |
| }}}))}); | |
| } | |
| TEST_F(SnapshotFixture_Platform5_Config0, GetProcessorTest) { | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, "system", | |
| "cpu0"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"].get<std::string>(), | |
| "/redfish/v1/Systems/system/Processors/cpu0"); | |
| EXPECT_EQ(json["Name"].get<std::string>(), "Processor"); | |
| EXPECT_EQ(json["Id"].get<std::string>(), "cpu0"); | |
| // cores and threads | |
| EXPECT_EQ(json["TotalCores"].get<int>(), 128); | |
| EXPECT_EQ(json["TotalThreads"].get<int>(), 256); | |
| EXPECT_EQ(json["TotalEnabledCores"].get<int>(), 128); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(SnapshotFixture, GetProcessorMaxTDP) { | |
| const std::string processorId = "cpu0"; | |
| const std::string systemName = "system"; | |
| const std::string pldmService = "xyz.openbmc_project.pldm"; | |
| const std::string effecterPath = | |
| "/xyz/openbmc_project/pldm/4/effecter/power/SOC_TDP_4"; | |
| const double tdpValue = 125.0; | |
| KeyType keySubtree(ManagedType::kManagedSubtree, "/xyz/openbmc_project/pldm", | |
| 0, {"xyz.openbmc_project.Effecter.Value"}); | |
| std::shared_ptr<ValueType> mockedSubtree = | |
| CreateValueType(CreateMapperGetSubTreeResponse()); | |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(keySubtree, mockedSubtree) | |
| .ok()); | |
| std::shared_ptr<ValueType> tdp_test_value = | |
| CreateValueType(DbusVariantType(tdpValue)); | |
| // Test case 1: Correct property "Value" exists | |
| KeyType pldmKey(ManagedType::kManagedProperty, pldmService, | |
| sdbusplus::message::object_path(effecterPath), | |
| "xyz.openbmc_project.Effecter.Value", "Value"); | |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(pldmKey, tdp_test_value) | |
| .ok()); | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, systemName, | |
| processorId); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| ASSERT_TRUE(json.contains("MaxTDPWatts")); | |
| EXPECT_EQ(json["MaxTDPWatts"], tdpValue); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| // Test case 2: Evict the key and make sure we don't see the property | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->evictMockObjectFromManagedStore(pldmKey) | |
| .ok()); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->evictMockObjectFromManagedStore(keySubtree) | |
| .ok()); | |
| share_async_resp_->res.clear(); | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, systemName, | |
| processorId); | |
| RunIoUntilDone(); | |
| ASSERT_FALSE(json.contains("MaxTDPWatts")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| // Test case 3: Insert the key again with an incorrect property name "Data" | |
| // instead of "Value" | |
| pldmKey = KeyType(ManagedType::kManagedProperty, pldmService, | |
| sdbusplus::message::object_path(effecterPath), | |
| "xyz.openbmc_project.Effecter.Value", "Data"); | |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(pldmKey, tdp_test_value) | |
| .ok()); | |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(keySubtree, mockedSubtree) | |
| .ok()); | |
| share_async_resp_->res.clear(); | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, systemName, | |
| processorId); | |
| RunIoUntilDone(); | |
| ASSERT_FALSE(json.contains("MaxTDPWatts")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| // Create a mocked response with an empty service map. | |
| // This will cause the code to log an error and continue, | |
| // not setting the MaxTDPWatts property. | |
| dbus::utility::MapperGetSubTreeResponse subtreeWithEmptyServiceMap( | |
| {std::make_pair("/xyz/openbmc_project/pldm/4/effecter/power/SOC_TDP_4", | |
| dbus::utility::MapperServiceMap({}))}); | |
| std::shared_ptr<ValueType> mockedSubtreeEmpty = | |
| CreateValueType(std::move(subtreeWithEmptyServiceMap)); | |
| EXPECT_TRUE( | |
| dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(keySubtree, mockedSubtreeEmpty) | |
| .ok()); | |
| share_async_resp_->res.clear(); | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, systemName, | |
| processorId); | |
| RunIoUntilDone(); | |
| ASSERT_FALSE(json.contains("MaxTDPWatts")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(ProcessorSnapshotFixture, GetProcessorMaxTDPInvalidServicePair) { | |
| const std::string processorId = "cpu0"; | |
| const std::string systemName = "system"; // system expects pldm | |
| const std::string pldmService = | |
| "xyz.openbmc_project.pldm0"; // but we provide pldm0 | |
| const std::string effecterPath = | |
| "/xyz/openbmc_project/pldm/4/effecter/power/SOC_TDP_4"; | |
| // This is the key for the getSubTree call in getProcessorMaxTDP | |
| KeyType keySubtree(ManagedType::kManagedSubtree, "/xyz/openbmc_project/pldm", | |
| 0, {"xyz.openbmc_project.Effecter.Value"}); | |
| // Create a mocked response for getSubTree | |
| dbus::utility::MapperGetSubTreeResponse mockSubtreeResponse( | |
| {std::make_pair(effecterPath, | |
| dbus::utility::MapperServiceMap( | |
| {{pldmService, // This is the invalid service | |
| {"xyz.openbmc_project.Effecter.Value"}}}))}); | |
| std::shared_ptr<ValueType> mockedSubtree = | |
| CreateValueType(std::move(mockSubtreeResponse)); | |
| EXPECT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(keySubtree, mockedSubtree) | |
| .ok()); | |
| // Call the handler | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, systemName, | |
| processorId); | |
| RunIoUntilDone(); | |
| // Check the response | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_FALSE(json.contains("MaxTDPWatts")); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(ProcessorSnapshotFixture, GetProcessorAndStateLinkTest) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.ProcessorState"}); | |
| MapperGetSubTreePathsResponse mockProcState = { | |
| "/xyz/openbmc_project/inventory/system/processorstate/PROC1", | |
| "/xyz/openbmc_project/inventory/system/processorstate/PROC2"}; | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType( | |
| std::move(mockProcState))) | |
| .ok()); | |
| handleProcessorGet(app_, CreateRequest(), share_async_resp_, "system", | |
| "cpu0"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"].get<std::string>(), | |
| "/redfish/v1/Systems/system/Processors/cpu0"); | |
| EXPECT_EQ(json["Name"].get<std::string>(), "Processor"); | |
| EXPECT_EQ(json["Id"].get<std::string>(), "cpu0"); | |
| EXPECT_TRUE(json.contains("/Oem/Google/ProcessorStates"_json_pointer)); | |
| auto processorStates = json["Oem"]["Google"]["ProcessorStates"]; | |
| EXPECT_EQ(processorStates[0]["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC1"); | |
| EXPECT_FALSE(processorStates[0].contains("Id")) | |
| << "Processor State got expanded at level 0"; | |
| EXPECT_EQ(processorStates[1]["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC2"); | |
| EXPECT_FALSE(processorStates[1].contains("Id")) | |
| << "Processor State got expanded at level 0"; | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| TEST_F(ProcessorSnapshotFixture, GetProcessorCollectionWithExpandOneTest) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.ProcessorState"}); | |
| MapperGetSubTreePathsResponse mockProcState = { | |
| "/xyz/openbmc_project/inventory/system/processorstate/PROC1", | |
| "/xyz/openbmc_project/inventory/system/processorstate/PROC2"}; | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType( | |
| std::move(mockProcState))) | |
| .ok()); | |
| query_param::Query delegatedQuery; | |
| delegatedQuery.expandLevel = 1; | |
| delegatedQuery.expandType = query_param::ExpandType::Both; | |
| handleProcessorCollection(share_async_resp_, delegatedQuery, ""); | |
| RunIoUntilDone(); | |
| EXPECT_TRUE(share_async_resp_->res.jsonValue.contains("Members")); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue["Members"][0]; | |
| EXPECT_EQ(json["@odata.id"].get<std::string>(), | |
| "/redfish/v1/Systems/system/Processors/cpu0"); | |
| EXPECT_EQ(json["Name"].get<std::string>(), "Processor"); | |
| EXPECT_EQ(json["Id"].get<std::string>(), "cpu0"); | |
| EXPECT_TRUE(json.contains("/Oem/Google/ProcessorStates"_json_pointer)); | |
| auto processorStates = json["Oem"]["Google"]["ProcessorStates"]; | |
| EXPECT_EQ(processorStates[0]["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC1"); | |
| EXPECT_FALSE(processorStates[0].contains("Id")) | |
| << "Processor State got expanded at level 0"; | |
| EXPECT_EQ(processorStates[1]["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC2"); | |
| EXPECT_FALSE(processorStates[1].contains("Id")) | |
| << "Processor State got expanded at level 0"; | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| void mockProcessorState(const std::string& processorState) { | |
| KeyType key(ManagedType::kManagedSubtreePaths, | |
| "/xyz/openbmc_project/inventory", 0, | |
| {"xyz.openbmc_project.Inventory.Item.ProcessorState"}); | |
| MapperGetSubTreePathsResponse mockProcState = { | |
| "/xyz/openbmc_project/inventory/system/processorstate/" + processorState}; | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore( | |
| key, managedStore::MockManagedStoreTest::CreateValueType( | |
| std::move(mockProcState))) | |
| .ok()); | |
| managedStore::KeyType presentKey( | |
| managedStore::ManagedType::kManagedProperty, | |
| "xyz.openbmc_project.EntityManager", | |
| {"/xyz/openbmc_project/inventory/system/processorstate/" + | |
| processorState}, | |
| "xyz.openbmc_project.Inventory.Item", "Present"); | |
| std::shared_ptr<ValueType> mockPresent = | |
| managedStore::MockManagedStoreTest::CreateValueType(std::move(true)); | |
| ASSERT_TRUE(dynamic_cast<managedStore::MockSerializedManagedObjectStore*>( | |
| managedStore::GetManagedObjectStore()) | |
| ->upsertMockObjectIntoManagedStore(presentKey, mockPresent) | |
| .ok()); | |
| } | |
| TEST_F(ProcessorSnapshotFixture, GetProcessorCollectionExpand2Test) { | |
| mockProcessorState("PROC1"); | |
| for (int i = 2; i <= 6; i++) { | |
| share_async_resp_ = std::make_shared<bmcweb::AsyncResp>(); | |
| query_param::Query delegatedQuery; | |
| delegatedQuery.expandLevel = i; | |
| delegatedQuery.expandType = query_param::ExpandType::Both; | |
| handleProcessorCollection(share_async_resp_, delegatedQuery, ""); | |
| RunIoUntilDone(); | |
| EXPECT_TRUE(share_async_resp_->res.jsonValue.contains("Members")); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue["Members"][0]; | |
| EXPECT_TRUE(json.contains("/Oem/Google/ProcessorStates"_json_pointer)); | |
| auto processorStates = json["Oem"]["Google"]["ProcessorStates"]; | |
| EXPECT_EQ(processorStates[0]["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC1"); | |
| EXPECT_TRUE(processorStates[0].contains("Id")) | |
| << "Processor State did not expand at level 2"; | |
| EXPECT_EQ(processorStates[0]["Id"], "PROC1"); | |
| EXPECT_EQ(processorStates[0]["Name"], "Processor"); | |
| EXPECT_EQ(processorStates[0]["@odata.type"], | |
| "#GoogleProcessorState.GoogleProcessorState"); | |
| EXPECT_EQ(processorStates[0]["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| } | |
| TEST_F(ProcessorSnapshotFixture, GetProcessorStateTest) { | |
| mockProcessorState("PROC1"); | |
| handleGetProcessorState(app_, CreateRequest(), share_async_resp_, "system", | |
| "cpu0", "PROC1"); | |
| RunIoUntilDone(); | |
| nlohmann::json& json = share_async_resp_->res.jsonValue; | |
| EXPECT_EQ(json["@odata.id"], | |
| "/redfish/v1/Systems/system/Processors/cpu0/Oem/Google/" | |
| "ProcessorStates/PROC1"); | |
| EXPECT_EQ(json["Id"], "PROC1"); | |
| EXPECT_EQ(json["Name"], "Processor"); | |
| EXPECT_EQ(json["@odata.type"], "#GoogleProcessorState.GoogleProcessorState"); | |
| EXPECT_EQ(json["Status"]["State"], "Enabled"); | |
| EXPECT_EQ(share_async_resp_->res.result(), boost::beast::http::status::ok); | |
| } | |
| } // namespace | |
| } // namespace redfish |