blob: 87bd9e8807756588196ea4444ed05769d45de7a6 [file]
#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);
}