| #include "common/test/mocked_utils.hpp" |
| #include "oem/intel/libpldmresponder/oem_intel_ras.hpp" |
| #include "oem/intel/oem_intel.hpp" |
| #include "pldmd/invoker.hpp" |
| |
| #include <endian.h> |
| #include <libpldm/base.h> |
| |
| #include <cstring> |
| #include <map> |
| #include <stdexcept> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| using namespace pldm; |
| using namespace pldm::responder; |
| using namespace pldm::responder::oem_intel; |
| using ::testing::_; |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::Throw; |
| |
| /** |
| * @class MockIntelRasHandler |
| * |
| * @brief Subclass of IntelRasHandler that mocks D-Bus method invocations |
| * for RasSetData and RasStart. |
| */ |
| class MockIntelRasHandler : public IntelRasHandler |
| { |
| public: |
| explicit MockIntelRasHandler( |
| const pldm::utils::DBusHandlerInterface* dBusHandler) : |
| IntelRasHandler(dBusHandler) |
| {} |
| |
| MOCK_METHOD(std::vector<uint8_t>, callRasSetData, |
| (const std::vector<uint8_t>&), (const override)); |
| MOCK_METHOD(void, callRasStart, (uint32_t), (const override)); |
| }; |
| |
| TEST(IntelRasHandlerTest, TestInvokerRegistration) |
| { |
| MockdBusHandler mockDBus; |
| Invoker invoker{}; |
| pldm::oem_intel::OemIntel oemIntel(&mockDBus, invoker, nullptr); |
| |
| // Verify that an unregistered command code throws std::out_of_range |
| uint8_t badCmd = 0xAA; |
| ASSERT_THROW(invoker.handle(0, PLDM_OEM, badCmd, nullptr, 0), |
| std::out_of_range); |
| } |
| |
| TEST(IntelRasHandlerTest, TestRasStateSuccessAndError) |
| { |
| MockdBusHandler mockDBus; |
| IntelRasHandler handler(&mockDBus); |
| |
| std::vector<uint8_t> reqMsg(sizeof(pldm_msg_hdr), 0); |
| auto req = reinterpret_cast<pldm_msg*>(reqMsg.data()); |
| req->hdr.instance_id = 1; |
| req->hdr.type = PLDM_OEM; |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_STATE); |
| |
| // 1. Success Case: Mock D-Bus property return |
| uint32_t expectedState = 0x12345678; |
| EXPECT_CALL(mockDBus, getDbusPropertyVariant( |
| StrEq("/com/intel/ras"), StrEq("RasState"), |
| StrEq("com.intel.RAS.Manager.Handshake"))) |
| .WillOnce(Return(pldm::utils::PropertyValue(expectedState))); |
| |
| auto resp = handler.getRasState(0, req, 0); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_SUCCESS); |
| |
| uint32_t actualStateLe = 0; |
| std::memcpy(&actualStateLe, &respPtr->payload[1], sizeof(actualStateLe)); |
| uint32_t actualState = le32toh(actualStateLe); |
| EXPECT_EQ(actualState, expectedState); |
| |
| // 2. Error Case: Mock D-Bus exception |
| EXPECT_CALL(mockDBus, getDbusPropertyVariant( |
| StrEq("/com/intel/ras"), StrEq("RasState"), |
| StrEq("com.intel.RAS.Manager.Handshake"))) |
| .WillOnce(Throw(std::runtime_error("D-Bus property get failed"))); |
| |
| resp = handler.getRasState(0, req, 0); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| } |
| |
| TEST(IntelRasHandlerTest, TestRasHandshakeSuccessAndError) |
| { |
| MockdBusHandler mockDBus; |
| IntelRasHandler handler(&mockDBus); |
| |
| std::vector<uint8_t> reqMsg(sizeof(pldm_msg_hdr), 0); |
| auto req = reinterpret_cast<pldm_msg*>(reqMsg.data()); |
| req->hdr.instance_id = 2; |
| req->hdr.type = PLDM_OEM; |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_HANDSHAKE); |
| |
| // 1. Success Case: Mock D-Bus property map |
| pldm::utils::PropertyMap mockProps = { |
| {"PcieCeSupported", pldm::utils::PropertyValue(true)}, |
| {"SpdRecoverySupported", pldm::utils::PropertyValue(false)}, |
| {"MemCeSupported", pldm::utils::PropertyValue(true)}, |
| {"UpiCeSupported", pldm::utils::PropertyValue(false)}, |
| {"McBanksSupported", pldm::utils::PropertyValue(true)}, |
| }; |
| |
| EXPECT_CALL(mockDBus, getDbusPropertiesVariant( |
| StrEq("com.intel.RAS"), StrEq("/com/intel/ras"), |
| StrEq("com.intel.RAS.Manager.Handshake"))) |
| .WillOnce(Return(mockProps)); |
| |
| auto resp = handler.getRasHandshake(0, req, 0); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_SUCCESS); |
| // Bit 0 (PcieCe=1), Bit 2 (MemCe=1), Bit 4 (McBanks=1) => 1 | 4 | 16 = 21 |
| // (0x15) |
| EXPECT_EQ(respPtr->payload[1], 0x15); |
| EXPECT_EQ(respPtr->payload[2], 0x00); // Reserved byte 1 |
| EXPECT_EQ(respPtr->payload[3], 0x00); // Reserved byte 2 |
| EXPECT_EQ(respPtr->payload[4], 0x00); // Reserved byte 3 |
| |
| // 2. Error Case: Mock D-Bus exception |
| EXPECT_CALL(mockDBus, getDbusPropertiesVariant( |
| StrEq("com.intel.RAS"), StrEq("/com/intel/ras"), |
| StrEq("com.intel.RAS.Manager.Handshake"))) |
| .WillOnce(Throw(std::runtime_error("D-Bus properties get failed"))); |
| |
| resp = handler.getRasHandshake(0, req, 0); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| } |
| |
| TEST(IntelRasHandlerTest, TestRasPolicyDataSuccessAndError) |
| { |
| MockdBusHandler mockDBus; |
| MockIntelRasHandler mockHandler(&mockDBus); |
| |
| std::vector<uint8_t> reqMsg(sizeof(pldm_msg_hdr) + 16, 0); |
| auto req = reinterpret_cast<pldm_msg*>(reqMsg.data()); |
| req->hdr.instance_id = 10; |
| req->hdr.type = PLDM_OEM; |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_POLICY_DATA); |
| std::fill(&req->payload[0], &req->payload[16], 0xAA); |
| |
| std::vector<uint8_t> expectedPayload(16, 0xAA); |
| std::vector<uint8_t> mockResponse = {0x00, 0x01}; |
| |
| // 1. Success Case: Expect callRasSetData with exact payload |
| EXPECT_CALL(mockHandler, callRasSetData(expectedPayload)) |
| .WillOnce(Return(mockResponse)); |
| |
| auto resp = mockHandler.processRasPolicyData(0, req, 16); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_SUCCESS); |
| EXPECT_EQ(respPtr->payload[1], 0x00); |
| EXPECT_EQ(respPtr->payload[2], 0x01); |
| |
| // 2. Error Case: Mock D-Bus exception |
| EXPECT_CALL(mockHandler, callRasSetData(expectedPayload)) |
| .WillOnce(Throw(std::runtime_error("D-Bus method call failed"))); |
| |
| resp = mockHandler.processRasPolicyData(0, req, 16); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| } |
| |
| TEST(IntelRasHandlerTest, TestRasStartSuccessAndError) |
| { |
| MockdBusHandler mockDBus; |
| MockIntelRasHandler mockHandler(&mockDBus); |
| |
| std::vector<uint8_t> startMsg(sizeof(pldm_msg_hdr) + 4, 0); |
| auto startReq = reinterpret_cast<pldm_msg*>(startMsg.data()); |
| startReq->hdr.instance_id = 20; |
| startReq->hdr.type = PLDM_OEM; |
| startReq->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_START); |
| |
| uint32_t rasStartList = 0x0000001F; |
| uint32_t rasStartListLe = htole32(rasStartList); |
| std::memcpy(startReq->payload, &rasStartListLe, sizeof(rasStartListLe)); |
| |
| // 1. Success Case |
| EXPECT_CALL(mockHandler, callRasStart(rasStartList)).Times(1); |
| auto resp = mockHandler.setRasStart(0, startReq, 4); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_SUCCESS); |
| |
| // 2. Error Case |
| EXPECT_CALL(mockHandler, callRasStart(rasStartList)) |
| .WillOnce(Throw(std::runtime_error("D-Bus method call failed"))); |
| resp = mockHandler.setRasStart(0, startReq, 4); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| } |
| |
| TEST(IntelRasHandlerTest, TestInvalidPayloadLengths) |
| { |
| MockdBusHandler mockDBus; |
| IntelRasHandler handler(&mockDBus); |
| |
| std::vector<uint8_t> reqMsg(sizeof(pldm_msg_hdr) + 2, 0); |
| auto req = reinterpret_cast<pldm_msg*>(reqMsg.data()); |
| req->hdr.instance_id = 25; |
| req->hdr.type = PLDM_OEM; |
| |
| // RasPolicyData requires non-zero payload |
| req->hdr.command = PLDM_OEM_INTEL_RAS_POLICY_DATA; |
| auto resp = handler.processRasPolicyData(0, req, 0); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_INVALID_LENGTH); |
| |
| // RasStart requires at least 4 bytes |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_START); |
| resp = handler.setRasStart(0, req, 2); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_INVALID_LENGTH); |
| } |
| |
| TEST(IntelRasHandlerTest, TestNullDBusHandler) |
| { |
| IntelRasHandler handler(nullptr); |
| |
| std::vector<uint8_t> reqMsg(sizeof(pldm_msg_hdr), 0); |
| auto req = reinterpret_cast<pldm_msg*>(reqMsg.data()); |
| req->hdr.instance_id = 1; |
| req->hdr.type = PLDM_OEM; |
| |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_STATE); |
| auto resp = handler.getRasState(0, req, 0); |
| auto respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| |
| req->hdr.command = |
| static_cast<uint8_t>(IntelRasCmds::PLDM_OEM_INTEL_RAS_HANDSHAKE); |
| resp = handler.getRasHandshake(0, req, 0); |
| respPtr = reinterpret_cast<pldm_msg*>(resp.data()); |
| EXPECT_EQ(respPtr->payload[0], PLDM_ERROR_NOT_READY); |
| } |