tests: Organize the test code to make it modular
The unit test code for libpldmresponder, host-bmc and common is
in a shared test directory. This patch separates the test code
to the respective directory.
Tested: Ran the unit test and tests passed.
Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: I31d53681fa6c0d8bc6eb7c4e3341aaff4bc341ee
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 7e52c3d..8436e14 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -52,3 +52,7 @@
libpldmresponder = declare_dependency(
link_with: libpldmresponder)
+
+if get_option('tests').enabled()
+ subdir('test')
+endif
diff --git a/libpldmresponder/test/bios_jsons/enum_attrs.json b/libpldmresponder/test/bios_jsons/enum_attrs.json
new file mode 100644
index 0000000..bee666f
--- /dev/null
+++ b/libpldmresponder/test/bios_jsons/enum_attrs.json
@@ -0,0 +1,60 @@
+{
+ "entries":[
+ {
+ "attribute_name" : "HMCManagedState",
+ "possible_values" : [ "On", "Off" ],
+ "default_values" : [ "On" ],
+ "readOnly" : false,
+ "helpText" : "HMCManagedState HelpText",
+ "displayName" : "HMCManagedState DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.HMCManaged.State",
+ "property_name" : "State",
+ "property_type" : "string",
+ "property_values" : ["xyz.openbmc_project.State.On", "xyz.openbmc_project.State.Off"]
+ }
+ },
+ {
+ "attribute_name" : "FWBootSide",
+ "possible_values" : [ "Perm", "Temp" ],
+ "default_values" : [ "Perm" ],
+ "readOnly" : false,
+ "helpText" : "FWBootSide HelpText",
+ "displayName" : "FWBootSide DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.FWBoot.Side",
+ "property_name" : "Side",
+ "property_type" : "bool",
+ "property_values" : [true, false]
+ }
+ },
+ {
+ "attribute_name" : "InbandCodeUpdate",
+ "possible_values" : [ "Allowed", "NotAllowed" ],
+ "default_values" : [ "Allowed" ],
+ "readOnly" : false,
+ "helpText" : "InbandCodeUpdate HelpText",
+ "displayName" : "InbandCodeUpdate DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.InBandCodeUpdate",
+ "property_name" : "Policy",
+ "property_type" : "uint8_t",
+ "property_values" : [0, 1]
+ }
+ },
+ {
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_values" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Concurrent" ],
+ "readOnly" : true,
+ "helpText" : "CodeUpdatePolicy HelpText",
+ "displayName" : "CodeUpdatePolicy DisplayName"
+ }
+ ]
+}
diff --git a/libpldmresponder/test/bios_jsons/integer_attrs.json b/libpldmresponder/test/bios_jsons/integer_attrs.json
new file mode 100644
index 0000000..e6833aa
--- /dev/null
+++ b/libpldmresponder/test/bios_jsons/integer_attrs.json
@@ -0,0 +1,40 @@
+{
+ "entries":[
+ {
+ "attribute_name" : "VDD_AVSBUS_RAIL",
+ "lower_bound" : 0,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 0,
+ "readOnly" : false,
+ "helpText" : "VDD_AVSBUS_RAIL HelpText",
+ "displayName" : "VDD_AVSBUS_RAIL DisplayName",
+ "dbus":{
+ "object_path" : "/xyz/openbmc_project/avsbus",
+ "interface" : "xyz.openbmc.AvsBus.Manager",
+ "property_type" : "uint8_t",
+ "property_name" : "Rail"
+ }
+ },
+ {
+ "attribute_name" : "SBE_IMAGE_MINIMUM_VALID_ECS",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 2,
+ "readOnly" : true,
+ "helpText" : "SBE_IMAGE_MINIMUM_VALID_ECS HelpText",
+ "displayName" : "SBE_IMAGE_MINIMUM_VALID_ECS DisplayName"
+ },
+ {
+ "attribute_name" : "INTEGER_INVALID_CASE",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 2,
+ "default_value" : 3,
+ "readOnly" : true,
+ "helpText" : "INTEGER_INVALID_CASE HelpText",
+ "displayName" : "INTEGER_INVALID_CASE DisplayName"
+ }
+ ]
+}
diff --git a/libpldmresponder/test/bios_jsons/string_attrs.json b/libpldmresponder/test/bios_jsons/string_attrs.json
new file mode 100644
index 0000000..09e0e4c
--- /dev/null
+++ b/libpldmresponder/test/bios_jsons/string_attrs.json
@@ -0,0 +1,49 @@
+{
+ "entries" : [
+ {
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "readOnly" : false,
+ "helpText" : "str_example1 HelpText",
+ "displayName" : "str_example1 DisplayName",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example1.value",
+ "property_name" : "Str_example1",
+ "property_type" : "string"
+ }
+ },
+ {
+ "attribute_name" : "str_example2",
+ "string_type" : "Hex",
+ "minimum_string_length" : 0,
+ "maximum_string_length" : 100,
+ "default_string_length" : 0,
+ "default_string" : "",
+ "readOnly" : false,
+ "helpText" : "str_example2 HelpText",
+ "displayName" : "str_example2 DisplayName",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example2.value",
+ "property_name" : "Str_example2",
+ "property_type" : "string"
+ }
+ },
+ {
+ "attribute_name" : "str_example3",
+ "string_type" : "Unknown",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 2,
+ "default_string" : "ef",
+ "readOnly" : true,
+ "helpText" : "str_example3 HelpText",
+ "displayName" : "str_example3 DisplayName"
+ }
+ ]
+}
diff --git a/libpldmresponder/test/event_jsons/good/event_state_sensor.json b/libpldmresponder/test/event_jsons/good/event_state_sensor.json
new file mode 100644
index 0000000..f10a319
--- /dev/null
+++ b/libpldmresponder/test/event_jsons/good/event_state_sensor.json
@@ -0,0 +1,66 @@
+{
+ "entries": [
+ {
+ "containerID": 1,
+ "entityType": 64,
+ "entityInstance": 1,
+ "sensorOffset": 0,
+ "event_states": [
+ 0,
+ 1,
+ 2
+ ],
+ "dbus": {
+ "object_path": "/xyz/abc/def",
+ "interface": "xyz.openbmc_project.example1.value",
+ "property_name": "value1",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.State.Normal",
+ "xyz.openbmc_project.State.Critical",
+ "xyz.openbmc_project.State.Fatal"
+ ]
+ }
+ },
+ {
+ "containerID": 1,
+ "entityType": 64,
+ "entityInstance": 1,
+ "sensorOffset": 1,
+ "event_states": [
+ 2,
+ 3
+ ],
+ "dbus": {
+ "object_path": "/xyz/abc/def",
+ "interface": "xyz.openbmc_project.example2.value",
+ "property_name": "value2",
+ "property_type": "uint8_t",
+ "property_values": [
+ 9,
+ 10
+ ]
+ }
+ },
+ {
+ "containerID": 2,
+ "entityType": 67,
+ "entityInstance": 2,
+ "sensorOffset": 0,
+ "event_states": [
+ 0,
+ 1
+ ],
+ "dbus": {
+ "object_path": "/xyz/abc/ghi",
+ "interface": "xyz.openbmc_project.example3.value",
+ "property_name": "value3",
+ "property_type": "bool",
+ "property_values": [
+ false,
+ true
+ ]
+ }
+ }
+ ]
+}
diff --git a/libpldmresponder/test/files/NVRAM-IMAGE b/libpldmresponder/test/files/NVRAM-IMAGE
new file mode 100644
index 0000000..06d7405
--- /dev/null
+++ b/libpldmresponder/test/files/NVRAM-IMAGE
Binary files differ
diff --git a/libpldmresponder/test/files/NVRAM-IMAGE-CKSUM b/libpldmresponder/test/files/NVRAM-IMAGE-CKSUM
new file mode 100644
index 0000000..01d633b
--- /dev/null
+++ b/libpldmresponder/test/files/NVRAM-IMAGE-CKSUM
Binary files differ
diff --git a/libpldmresponder/test/fru_jsons/good/Board_General.json b/libpldmresponder/test/fru_jsons/good/Board_General.json
new file mode 100644
index 0000000..d4efdab
--- /dev/null
+++ b/libpldmresponder/test/fru_jsons/good/Board_General.json
@@ -0,0 +1,29 @@
+{
+ "record_details":
+ {
+ "fru_record_type" : 1,
+ "fru_encoding_type": 1,
+ "dbus_interface_name": "xyz.openbmc_project.Inventory.Item.Board"
+ },
+ "fru_fields":[
+ {
+ "fru_field_type" : 3,
+ "dbus":
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Decorator.Asset",
+ "property_name" : "PartNumber",
+ "property_type" : "string"
+ }
+ },
+ {
+ "fru_field_type" : 4,
+ "dbus":
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Decorator.Asset",
+ "property_name" : "SerialNumber",
+ "property_type" : "string"
+ }
+ }
+ ]
+}
+
diff --git a/libpldmresponder/test/fru_jsons/good/Board_VINI.json b/libpldmresponder/test/fru_jsons/good/Board_VINI.json
new file mode 100644
index 0000000..1ef87ef
--- /dev/null
+++ b/libpldmresponder/test/fru_jsons/good/Board_VINI.json
@@ -0,0 +1,30 @@
+{
+ "record_details":
+ {
+ "fru_record_type" : 254,
+ "fru_encoding_type": 1,
+ "dbus_interface_name": "xyz.openbmc_project.Inventory.Item.Board"
+ },
+ "fru_fields":[
+ {
+ "fru_field_type" : 2,
+ "dbus":
+ {
+ "interface" : "com.ibm.ipzvpd.VINI",
+ "property_name" : "RT",
+ "property_type" : "string"
+ }
+ },
+ {
+ "fru_field_type" : 3,
+ "dbus":
+ {
+ "interface" : "com.ibm.ipzvpd.VINI",
+ "property_name" : "B3",
+ "property_type" : "bytearray"
+ }
+ }
+
+ ]
+}
+
diff --git a/libpldmresponder/test/fru_jsons/good/Cpu_General.json b/libpldmresponder/test/fru_jsons/good/Cpu_General.json
new file mode 100644
index 0000000..01a378a
--- /dev/null
+++ b/libpldmresponder/test/fru_jsons/good/Cpu_General.json
@@ -0,0 +1,28 @@
+{
+ "record_details":
+ {
+ "fru_record_type" : 1,
+ "fru_encoding_type": 1,
+ "dbus_interface_name": "xyz.openbmc_project.Inventory.Item.Cpu"
+ },
+ "fru_fields":[
+ {
+ "fru_field_type" : 3,
+ "dbus":
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Decorator.Asset",
+ "property_name" : "PartNumber",
+ "property_type" : "string"
+ }
+ },
+ {
+ "fru_field_type" : 4,
+ "dbus":
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Decorator.Asset",
+ "property_name" : "SerialNumber",
+ "property_type" : "string"
+ }
+ }
+ ]
+}
diff --git a/libpldmresponder/test/fru_jsons/good/FRU_Master.json b/libpldmresponder/test/fru_jsons/good/FRU_Master.json
new file mode 100644
index 0000000..fa2c405
--- /dev/null
+++ b/libpldmresponder/test/fru_jsons/good/FRU_Master.json
@@ -0,0 +1,14 @@
+{
+ "service":"xyz.openbmc_project.Inventory.Manager",
+ "root_path":"/xyz/openbmc_project/inventory/system/",
+ "entities":[
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Item.Board",
+ "entity_type" : 64
+ },
+ {
+ "interface" : "xyz.openbmc_project.Inventory.Item.Cpu",
+ "entity_type" : 135
+ }
+ ]
+}
diff --git a/libpldmresponder/test/libpldmresponder_base_test.cpp b/libpldmresponder/test/libpldmresponder_base_test.cpp
new file mode 100644
index 0000000..ac6e681
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_base_test.cpp
@@ -0,0 +1,140 @@
+#include "libpldm/base.h"
+
+#include "libpldmresponder/base.hpp"
+
+#include <string.h>
+
+#include <array>
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder;
+
+TEST(GetPLDMTypes, testGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr)> requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ // payload length will be 0 in this case
+ size_t requestPayloadLength = 0;
+ base::Handler handler;
+ auto response = handler.getPLDMTypes(request, requestPayloadLength);
+ // Need to support OEM type.
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ uint8_t* payload_ptr = responsePtr->payload;
+ ASSERT_EQ(payload_ptr[0], 0);
+ ASSERT_EQ(payload_ptr[1], 29); // 0b11101 see DSP0240 table11
+ ASSERT_EQ(payload_ptr[2], 0);
+}
+
+TEST(GetPLDMCommands, testGoodRequest)
+{
+ // Need to support OEM type commands.
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+ base::Handler handler;
+ auto response = handler.getPLDMCommands(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ uint8_t* payload_ptr = responsePtr->payload;
+ ASSERT_EQ(payload_ptr[0], 0);
+ ASSERT_EQ(payload_ptr[1], 60); // 60 = 0b111100
+ ASSERT_EQ(payload_ptr[2], 0);
+}
+
+TEST(GetPLDMCommands, testBadRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+
+ request->payload[0] = 0xFF;
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+ base::Handler handler;
+ auto response = handler.getPLDMCommands(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ uint8_t* payload_ptr = responsePtr->payload;
+ ASSERT_EQ(payload_ptr[0], PLDM_ERROR_INVALID_PLDM_TYPE);
+}
+TEST(GetPLDMVersion, testGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ uint8_t pldmType = PLDM_BASE;
+ uint32_t transferHandle = 0x0;
+ uint8_t flag = PLDM_GET_FIRSTPART;
+ uint8_t retFlag = PLDM_START_AND_END;
+ ver32_t version = {0xF1, 0xF0, 0xF0, 0x00};
+
+ auto rc =
+ encode_get_version_req(0, transferHandle, flag, pldmType, request);
+
+ ASSERT_EQ(0, rc);
+
+ base::Handler handler;
+ auto response = handler.getPLDMVersion(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ ASSERT_EQ(responsePtr->payload[0], 0);
+ ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
+ &transferHandle, sizeof(transferHandle)));
+ ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]) +
+ sizeof(transferHandle),
+ &retFlag, sizeof(flag)));
+ ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]) +
+ sizeof(transferHandle) + sizeof(flag),
+ &version, sizeof(version)));
+}
+TEST(GetPLDMVersion, testBadRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ uint8_t pldmType = 7;
+ uint32_t transferHandle = 0x0;
+ uint8_t flag = PLDM_GET_FIRSTPART;
+
+ auto rc =
+ encode_get_version_req(0, transferHandle, flag, pldmType, request);
+
+ ASSERT_EQ(0, rc);
+
+ base::Handler handler;
+ auto response = handler.getPLDMVersion(request, requestPayloadLength - 1);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
+
+ request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ rc = encode_get_version_req(0, transferHandle, flag, pldmType, request);
+
+ ASSERT_EQ(0, rc);
+
+ response = handler.getPLDMVersion(request, requestPayloadLength);
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_PLDM_TYPE);
+}
+
+TEST(GetTID, testGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr)> requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = 0;
+
+ base::Handler handler;
+ auto response = handler.getTID(request, requestPayloadLength);
+
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ uint8_t* payload = responsePtr->payload;
+
+ ASSERT_EQ(payload[0], 0);
+ ASSERT_EQ(payload[1], 1);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_attribute_test.cpp b/libpldmresponder/test/libpldmresponder_bios_attribute_test.cpp
new file mode 100644
index 0000000..f7b9d50
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_attribute_test.cpp
@@ -0,0 +1,99 @@
+#include "libpldmresponder/bios_attribute.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder::bios;
+
+class TestAttribute : public BIOSAttribute
+{
+ public:
+ TestAttribute(const Json& entry, DBusHandler* const dbusHandler) :
+ BIOSAttribute(entry, dbusHandler)
+ {}
+
+ void setAttrValueOnDbus(const pldm_bios_attr_val_table_entry*,
+ const pldm_bios_attr_table_entry*,
+ const BIOSStringTable&) override
+ {}
+
+ void constructEntry(
+ const BIOSStringTable&, Table&, Table&,
+ std::optional<std::variant<int64_t, std::string>>) override
+ {}
+
+ const std::optional<DBusMapping>& getDbusMap()
+ {
+ return dBusMap;
+ }
+
+ int updateAttrVal(Table& /*newValue*/, uint16_t /*attrHdl*/,
+ uint8_t /*attrType*/,
+ const PropertyValue& /*newPropVal*/) override
+ {
+ return PLDM_SUCCESS;
+ }
+
+ void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& /*attributevalue*/,
+ Table& /*attrValueEntry*/)
+ {}
+};
+
+TEST(BIOSAttribute, CtorTest)
+{
+ auto jsonReadOnly = R"({
+ "attribute_name" : "ReadOnly",
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ TestAttribute readOnly{jsonReadOnly, nullptr};
+ EXPECT_EQ(readOnly.name, "ReadOnly");
+ EXPECT_EQ(readOnly.readOnly, true);
+
+ auto jsonReadOnlyError = R"({
+ "attribute_nam":"ReadOnly"
+ })"_json;
+ using Json = nlohmann::json;
+
+ EXPECT_THROW((TestAttribute{jsonReadOnlyError, nullptr}), Json::exception);
+
+ auto jsonReadWrite = R"({
+ "attribute_name":"ReadWrite",
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.FWBoot.Side",
+ "property_name" : "Side",
+ "property_type" : "bool"
+ }
+ })"_json;
+
+ TestAttribute readWrite{jsonReadWrite, nullptr};
+ EXPECT_EQ(readWrite.name, "ReadWrite");
+ EXPECT_EQ(readWrite.readOnly, false);
+ auto dbusMap = readWrite.getDbusMap();
+ EXPECT_NE(dbusMap, std::nullopt);
+ EXPECT_EQ(dbusMap->objectPath, "/xyz/abc/def");
+ EXPECT_EQ(dbusMap->interface, "xyz.openbmc.FWBoot.Side");
+ EXPECT_EQ(dbusMap->propertyName, "Side");
+ EXPECT_EQ(dbusMap->propertyType, "bool");
+
+ auto jsonReadWriteError = R"({
+ "attribute_name":"ReadWrite",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.FWBoot.Side",
+ "property_name" : "Side"
+ }
+ })"_json; // missing property_type.
+
+ EXPECT_THROW((TestAttribute{jsonReadWriteError, nullptr}), Json::exception);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_config_test.cpp b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
new file mode 100644
index 0000000..25300ca
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
@@ -0,0 +1,318 @@
+#include "common/bios_utils.hpp"
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/bios_config.hpp"
+#include "libpldmresponder/bios_string_attribute.hpp"
+#include "mocked_bios.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <fstream>
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm::bios::utils;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Throw;
+
+class TestBIOSConfig : public ::testing::Test
+{
+ public:
+ static void SetUpTestCase() // will execute once at the begining of all
+ // TestBIOSConfig objects
+ {
+ char tmpdir[] = "/tmp/BIOSTables.XXXXXX";
+ tableDir = fs::path(mkdtemp(tmpdir));
+
+ std::vector<fs::path> paths = {
+ "./bios_jsons/string_attrs.json",
+ "./bios_jsons/integer_attrs.json",
+ "./bios_jsons/enum_attrs.json",
+ };
+
+ for (auto& path : paths)
+ {
+ std::ifstream file;
+ file.open(path);
+ auto j = Json::parse(file);
+ jsons.emplace_back(j);
+ }
+ }
+
+ std::optional<Json> findJsonEntry(const std::string& name)
+ {
+ for (auto& json : jsons)
+ {
+ auto entries = json.at("entries");
+ for (auto& entry : entries)
+ {
+ auto n = entry.at("attribute_name").get<std::string>();
+ if (n == name)
+ {
+ return entry;
+ }
+ }
+ }
+ return std::nullopt;
+ }
+
+ static void TearDownTestCase() // will be executed once at th end of all
+ // TestBIOSConfig objects
+ {
+ fs::remove_all(tableDir);
+ }
+
+ static fs::path tableDir;
+ static std::vector<Json> jsons;
+};
+
+fs::path TestBIOSConfig::tableDir;
+std::vector<Json> TestBIOSConfig::jsons;
+
+TEST_F(TestBIOSConfig, buildTablesTest)
+{
+ MockdBusHandler dbusHandler;
+
+ ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
+ .WillByDefault(Throw(std::exception()));
+
+ BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
+ nullptr);
+ biosConfig.buildTables();
+
+ auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+ auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+ EXPECT_TRUE(stringTable);
+ EXPECT_TRUE(attrTable);
+ EXPECT_TRUE(attrValueTable);
+
+ std::set<std::string> expectedStrings = {"HMCManagedState",
+ "On",
+ "Off",
+ "FWBootSide",
+ "Perm",
+ "Temp",
+ "InbandCodeUpdate",
+ "Allowed",
+ "NotAllowed",
+ "CodeUpdatePolicy",
+ "Concurrent",
+ "Disruptive",
+ "VDD_AVSBUS_RAIL",
+ "SBE_IMAGE_MINIMUM_VALID_ECS",
+ "INTEGER_INVALID_CASE",
+ "str_example1",
+ "str_example2",
+ "str_example3"};
+ std::set<std::string> strings;
+ for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>(
+ stringTable->data(), stringTable->size()))
+ {
+ auto str = table::string::decodeString(entry);
+ strings.emplace(str);
+ }
+
+ EXPECT_EQ(strings, expectedStrings);
+
+ BIOSStringTable biosStringTable(*stringTable);
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+ attrTable->size()))
+ {
+ auto header = table::attribute::decodeHeader(entry);
+ auto attrName = biosStringTable.findString(header.stringHandle);
+ auto jsonEntry = findJsonEntry(attrName);
+ EXPECT_TRUE(jsonEntry);
+ switch (header.attrType)
+ {
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ {
+ auto stringField = table::attribute::decodeStringEntry(entry);
+ auto stringType = BIOSStringAttribute::strTypeMap.at(
+ jsonEntry->at("string_type").get<std::string>());
+ EXPECT_EQ(stringField.stringType,
+ static_cast<uint8_t>(stringType));
+
+ EXPECT_EQ(
+ stringField.minLength,
+ jsonEntry->at("minimum_string_length").get<uint16_t>());
+ EXPECT_EQ(
+ stringField.maxLength,
+ jsonEntry->at("maximum_string_length").get<uint16_t>());
+ EXPECT_EQ(
+ stringField.defLength,
+ jsonEntry->at("default_string_length").get<uint16_t>());
+ EXPECT_EQ(stringField.defString,
+ jsonEntry->at("default_string").get<std::string>());
+ break;
+ }
+ case PLDM_BIOS_INTEGER:
+ case PLDM_BIOS_INTEGER_READ_ONLY:
+ {
+ auto integerField = table::attribute::decodeIntegerEntry(entry);
+ EXPECT_EQ(integerField.lowerBound,
+ jsonEntry->at("lower_bound").get<uint64_t>());
+ EXPECT_EQ(integerField.upperBound,
+ jsonEntry->at("upper_bound").get<uint64_t>());
+ EXPECT_EQ(integerField.scalarIncrement,
+ jsonEntry->at("scalar_increment").get<uint32_t>());
+ EXPECT_EQ(integerField.defaultValue,
+ jsonEntry->at("default_value").get<uint64_t>());
+ break;
+ }
+ case PLDM_BIOS_ENUMERATION:
+ case PLDM_BIOS_ENUMERATION_READ_ONLY:
+ {
+ auto [pvHdls, defInds] =
+ table::attribute::decodeEnumEntry(entry);
+ auto possibleValues = jsonEntry->at("possible_values")
+ .get<std::vector<std::string>>();
+ std::vector<std::string> strings;
+ for (auto pv : pvHdls)
+ {
+ auto s = biosStringTable.findString(pv);
+ strings.emplace_back(s);
+ }
+ EXPECT_EQ(strings, possibleValues);
+ EXPECT_EQ(defInds.size(), 1);
+
+ auto defValue = biosStringTable.findString(pvHdls[defInds[0]]);
+ auto defaultValues = jsonEntry->at("default_values")
+ .get<std::vector<std::string>>();
+ EXPECT_EQ(defValue, defaultValues[0]);
+
+ break;
+ }
+ default:
+ EXPECT_TRUE(false);
+ break;
+ }
+ }
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+ attrValueTable->data(), attrValueTable->size()))
+ {
+ auto header = table::attribute_value::decodeHeader(entry);
+ auto attrEntry =
+ table::attribute::findByHandle(*attrTable, header.attrHandle);
+ auto attrHeader = table::attribute::decodeHeader(attrEntry);
+ auto attrName = biosStringTable.findString(attrHeader.stringHandle);
+ auto jsonEntry = findJsonEntry(attrName);
+ EXPECT_TRUE(jsonEntry);
+ switch (header.attrType)
+ {
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ {
+ auto value = table::attribute_value::decodeStringEntry(entry);
+ auto defValue =
+ jsonEntry->at("default_string").get<std::string>();
+ EXPECT_EQ(value, defValue);
+ break;
+ }
+ case PLDM_BIOS_INTEGER:
+ case PLDM_BIOS_INTEGER_READ_ONLY:
+ {
+ auto value = table::attribute_value::decodeIntegerEntry(entry);
+ auto defValue = jsonEntry->at("default_value").get<uint64_t>();
+ EXPECT_EQ(value, defValue);
+ break;
+ }
+ case PLDM_BIOS_ENUMERATION:
+ case PLDM_BIOS_ENUMERATION_READ_ONLY:
+ {
+ auto indices = table::attribute_value::decodeEnumEntry(entry);
+ EXPECT_EQ(indices.size(), 1);
+ auto possibleValues = jsonEntry->at("possible_values")
+ .get<std::vector<std::string>>();
+
+ auto defValues = jsonEntry->at("default_values")
+ .get<std::vector<std::string>>();
+ EXPECT_EQ(possibleValues[indices[0]], defValues[0]);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false);
+ break;
+ }
+ }
+}
+
+TEST_F(TestBIOSConfig, setAttrValue)
+{
+ MockdBusHandler dbusHandler;
+
+ BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
+ nullptr);
+ biosConfig.removeTables();
+ biosConfig.buildTables();
+
+ auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+ BIOSStringTable biosStringTable(*stringTable);
+ BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(),
+ attrTable->size());
+ auto stringHandle = biosStringTable.findHandle("str_example1");
+ uint16_t attrHandle{};
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+ attrTable->size()))
+ {
+ auto header = table::attribute::decodeHeader(entry);
+ if (header.stringHandle == stringHandle)
+ {
+ attrHandle = header.attrHandle;
+ break;
+ }
+ }
+
+ EXPECT_NE(attrHandle, 0);
+
+ std::vector<uint8_t> attrValueEntry{
+ 0, 0, /* attr handle */
+ 1, /* attr type string read-write */
+ 4, 0, /* current string length */
+ 'a', 'b', 'c', 'd', /* defaut value string handle index */
+ };
+
+ attrValueEntry[0] = attrHandle & 0xff;
+ attrValueEntry[1] = (attrHandle >> 8) & 0xff;
+
+ DBusMapping dbusMapping{"/xyz/abc/def",
+ "xyz.openbmc_project.str_example1.value",
+ "Str_example1", "string"};
+ PropertyValue value = std::string("abcd");
+ EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1);
+
+ auto rc =
+ biosConfig.setAttrValue(attrValueEntry.data(), attrValueEntry.size());
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+
+ auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+ auto findEntry =
+ [&attrValueTable](
+ uint16_t handle) -> const pldm_bios_attr_val_table_entry* {
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+ attrValueTable->data(), attrValueTable->size()))
+ {
+ auto [attrHandle, _] = table::attribute_value::decodeHeader(entry);
+ if (attrHandle == handle)
+ return entry;
+ }
+ return nullptr;
+ };
+
+ auto entry = findEntry(attrHandle);
+ EXPECT_NE(entry, nullptr);
+
+ auto p = reinterpret_cast<const uint8_t*>(entry);
+ EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()),
+ ElementsAreArray(attrValueEntry));
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_enum_attribute_test.cpp b/libpldmresponder/test/libpldmresponder_bios_enum_attribute_test.cpp
new file mode 100644
index 0000000..08d960d
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_enum_attribute_test.cpp
@@ -0,0 +1,231 @@
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/bios_enum_attribute.hpp"
+#include "mocked_bios.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Throw;
+
+class TestBIOSEnumAttribute : public ::testing::Test
+{
+ public:
+ const auto& getPossibleValues(const BIOSEnumAttribute& attribute)
+ {
+ return attribute.possibleValues;
+ }
+
+ const auto& getDefaultValue(const BIOSEnumAttribute& attribute)
+ {
+ return attribute.defaultValue;
+ }
+};
+
+TEST_F(TestBIOSEnumAttribute, CtorTest)
+{
+ auto jsonEnumReadOnly = R"({
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_values" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Concurrent" ],
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ BIOSEnumAttribute enumReadOnly{jsonEnumReadOnly, nullptr};
+ EXPECT_EQ(enumReadOnly.name, "CodeUpdatePolicy");
+ EXPECT_TRUE(enumReadOnly.readOnly);
+ EXPECT_THAT(getPossibleValues(enumReadOnly),
+ ElementsAreArray({"Concurrent", "Disruptive"}));
+ EXPECT_EQ(getDefaultValue(enumReadOnly), "Concurrent");
+
+ auto jsonEnumReadOnlyError = R"({
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_value" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Concurrent" ],
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json; // possible_value -> possible_values
+ EXPECT_THROW((BIOSEnumAttribute{jsonEnumReadOnlyError, nullptr}),
+ Json::exception);
+
+ auto jsonEnumReadWrite = R"({
+ "attribute_name" : "FWBootSide",
+ "possible_values" : [ "Perm", "Temp" ],
+ "default_values" : [ "Perm" ],
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.FWBoot.Side",
+ "property_name" : "Side",
+ "property_type" : "bool",
+ "property_values" : [true, false]
+ }
+ })"_json;
+
+ BIOSEnumAttribute enumReadWrite{jsonEnumReadWrite, nullptr};
+ EXPECT_EQ(enumReadWrite.name, "FWBootSide");
+ EXPECT_TRUE(!enumReadWrite.readOnly);
+}
+
+TEST_F(TestBIOSEnumAttribute, ConstructEntry)
+{
+ MockBIOSStringTable biosStringTable;
+ MockdBusHandler dbusHandler;
+
+ auto jsonEnumReadOnly = R"({
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_values" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Disruptive" ],
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ std::vector<uint8_t> expectedAttrEntry{
+ 0, 0, /* attr handle */
+ 0x80, /* attr type enum read-only*/
+ 4, 0, /* attr name handle */
+ 2, /* number of possible value */
+ 2, 0, /* possible value handle */
+ 3, 0, /* possible value handle */
+ 1, /* number of default value */
+ 1 /* defaut value string handle index */
+ };
+
+ std::vector<uint8_t> expectedAttrValueEntry{
+ 0, 0, /* attr handle */
+ 0x80, /* attr type enum read-only*/
+ 1, /* number of current value */
+ 1 /* current value string handle index */
+ };
+
+ BIOSEnumAttribute enumReadOnly{jsonEnumReadOnly, nullptr};
+
+ ON_CALL(biosStringTable, findHandle(StrEq("Concurrent")))
+ .WillByDefault(Return(2));
+ ON_CALL(biosStringTable, findHandle(StrEq("Disruptive")))
+ .WillByDefault(Return(3));
+ ON_CALL(biosStringTable, findHandle(StrEq("CodeUpdatePolicy")))
+ .WillByDefault(Return(4));
+
+ checkConstructEntry(enumReadOnly, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ auto jsonEnumReadWrite = R"({
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_values" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Disruptive" ],
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.abc.def",
+ "property_name" : "Policy",
+ "property_type" : "bool",
+ "property_values" : [true, false]
+ }
+ })"_json;
+
+ BIOSEnumAttribute enumReadWrite{jsonEnumReadWrite, &dbusHandler};
+
+ EXPECT_CALL(dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/abc/def"), StrEq("Policy"),
+ StrEq("xyz.openbmc.abc.def")))
+ .WillOnce(Throw(std::exception()));
+
+ /* Set expected attr type to read-write */
+ expectedAttrEntry[2] = PLDM_BIOS_ENUMERATION;
+ expectedAttrValueEntry[2] = PLDM_BIOS_ENUMERATION;
+
+ checkConstructEntry(enumReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ EXPECT_CALL(dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/abc/def"), StrEq("Policy"),
+ StrEq("xyz.openbmc.abc.def")))
+ .WillOnce(Return(PropertyValue(true)));
+
+ expectedAttrValueEntry = {
+ 0, 0, /* attr handle */
+ 0, /* attr type enum read-write*/
+ 1, /* number of current value */
+ 0 /* current value string handle index */
+ };
+
+ checkConstructEntry(enumReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+}
+
+TEST_F(TestBIOSEnumAttribute, setAttrValueOnDbus)
+{
+ MockBIOSStringTable biosStringTable;
+ MockdBusHandler dbusHandler;
+
+ auto jsonEnumReadWrite = R"({
+ "attribute_name" : "CodeUpdatePolicy",
+ "possible_values" : [ "Concurrent", "Disruptive" ],
+ "default_values" : [ "Disruptive" ],
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":
+ {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc.abc.def",
+ "property_name" : "Policy",
+ "property_type" : "bool",
+ "property_values" : [true, false]
+ }
+ })"_json;
+ DBusMapping dbusMapping{"/xyz/abc/def", "xyz.openbmc.abc.def", "Policy",
+ "bool"};
+
+ BIOSEnumAttribute enumReadWrite{jsonEnumReadWrite, &dbusHandler};
+
+ std::vector<uint8_t> attrEntry{
+ 0, 0, /* attr handle */
+ 0, /* attr type enum read-only*/
+ 4, 0, /* attr name handle */
+ 2, /* number of possible value */
+ 2, 0, /* possible value handle */
+ 3, 0, /* possible value handle */
+ 1, /* number of default value */
+ 1 /* defaut value string handle index */
+ };
+
+ ON_CALL(biosStringTable, findString(2))
+ .WillByDefault(Return(std::string("Concurrent")));
+ ON_CALL(biosStringTable, findString(3))
+ .WillByDefault(Return(std::string("Disruptive")));
+
+ std::vector<uint8_t> attrValueEntry{
+ 0, 0, /* attr handle */
+ 0, /* attr type enum read-only*/
+ 1, /* number of current value */
+ 0 /* current value string handle index */
+ };
+
+ EXPECT_CALL(dbusHandler,
+ setDbusProperty(dbusMapping, PropertyValue{bool(true)}))
+ .Times(1);
+ enumReadWrite.setAttrValueOnDbus(
+ reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data()),
+ reinterpret_cast<pldm_bios_attr_table_entry*>(attrEntry.data()),
+ biosStringTable);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_integer_attribute_test.cpp b/libpldmresponder/test/libpldmresponder_bios_integer_attribute_test.cpp
new file mode 100644
index 0000000..fe1d6a8
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_integer_attribute_test.cpp
@@ -0,0 +1,206 @@
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/bios_integer_attribute.hpp"
+#include "mocked_bios.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Throw;
+
+class TestBIOSIntegerAttribute : public ::testing::Test
+{
+ public:
+ const auto& getIntegerInfo(const BIOSIntegerAttribute& attribute)
+ {
+ return attribute.integerInfo;
+ }
+};
+
+TEST_F(TestBIOSIntegerAttribute, CtorTest)
+{
+ auto jsonIntegerReadOnly = R"({
+ "attribute_name" : "SBE_IMAGE_MINIMUM_VALID_ECS",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 2,
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ BIOSIntegerAttribute integerReadOnly{jsonIntegerReadOnly, nullptr};
+ EXPECT_EQ(integerReadOnly.name, "SBE_IMAGE_MINIMUM_VALID_ECS");
+ EXPECT_TRUE(integerReadOnly.readOnly);
+ auto& integerInfo = getIntegerInfo(integerReadOnly);
+ EXPECT_EQ(integerInfo.lowerBound, 1);
+ EXPECT_EQ(integerInfo.upperBound, 15);
+ EXPECT_EQ(integerInfo.scalarIncrement, 1);
+ EXPECT_EQ(integerInfo.defaultValue, 2);
+
+ auto jsonIntegerReadOnlyError = R"({
+ "attribute_name" : "SBE_IMAGE_MINIMUM_VALID_ECS",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_valu" : 2,
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json; // default_valu -> default_value
+ EXPECT_THROW((BIOSIntegerAttribute{jsonIntegerReadOnlyError, nullptr}),
+ Json::exception);
+
+ auto jsonIntegerReadWrite = R"({
+ "attribute_name" : "VDD_AVSBUS_RAIL",
+ "lower_bound" : 0,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 0,
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":{
+ "object_path" : "/xyz/openbmc_project/avsbus",
+ "interface" : "xyz.openbmc.AvsBus.Manager",
+ "property_type" : "uint8_t",
+ "property_name" : "Rail"
+ }
+ })"_json;
+
+ BIOSIntegerAttribute integerReadWrite{jsonIntegerReadWrite, nullptr};
+ EXPECT_EQ(integerReadWrite.name, "VDD_AVSBUS_RAIL");
+ EXPECT_TRUE(!integerReadWrite.readOnly);
+}
+
+TEST_F(TestBIOSIntegerAttribute, ConstructEntry)
+{
+ MockBIOSStringTable biosStringTable;
+ MockdBusHandler dbusHandler;
+
+ auto jsonIntegerReadOnly = R"({
+ "attribute_name" : "VDD_AVSBUS_RAIL",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 2,
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ std::vector<uint8_t> expectedAttrEntry{
+ 0, 0, /* attr handle */
+ 0x83, /* attr type integer read-only*/
+ 5, 0, /* attr name handle */
+ 1, 0, 0, 0, 0, 0, 0, 0, /* lower bound */
+ 15, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+ 1, 0, 0, 0, /* scalar increment */
+ 2, 0, 0, 0, 0, 0, 0, 0, /* defaut value */
+ };
+ std::vector<uint8_t> expectedAttrValueEntry{
+ 0, 0, /* attr handle */
+ 0x83, /* attr type integer read-only*/
+ 2, 0, 0, 0, 0, 0, 0, 0, /* current value */
+ };
+
+ BIOSIntegerAttribute integerReadOnly{jsonIntegerReadOnly, nullptr};
+
+ ON_CALL(biosStringTable, findHandle(StrEq("VDD_AVSBUS_RAIL")))
+ .WillByDefault(Return(5));
+
+ checkConstructEntry(integerReadOnly, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ auto jsonIntegerReadWrite = R"({
+ "attribute_name" : "VDD_AVSBUS_RAIL",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 2,
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":{
+ "object_path" : "/xyz/openbmc_project/avsbus",
+ "interface" : "xyz.openbmc.AvsBus.Manager",
+ "property_type" : "uint8_t",
+ "property_name" : "Rail"
+ }
+ })"_json;
+ BIOSIntegerAttribute integerReadWrite{jsonIntegerReadWrite, &dbusHandler};
+
+ EXPECT_CALL(dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/openbmc_project/avsbus"),
+ StrEq("Rail"),
+ StrEq("xyz.openbmc.AvsBus.Manager")))
+ .WillOnce(Throw(std::exception()));
+
+ /* Set expected attr type to read-write */
+ expectedAttrEntry[2] = PLDM_BIOS_INTEGER;
+ expectedAttrValueEntry[2] = PLDM_BIOS_INTEGER;
+
+ checkConstructEntry(integerReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ EXPECT_CALL(dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/openbmc_project/avsbus"),
+ StrEq("Rail"),
+ StrEq("xyz.openbmc.AvsBus.Manager")))
+ .WillOnce(Return(PropertyValue(uint8_t(7))));
+
+ expectedAttrValueEntry = {
+ 0, 0, /* attr handle */
+ 3, /* attr type integer read-write*/
+ 7, 0, 0, 0, 0, 0, 0, 0, /* current value */
+ };
+
+ checkConstructEntry(integerReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+}
+
+TEST_F(TestBIOSIntegerAttribute, setAttrValueOnDbus)
+{
+ MockdBusHandler dbusHandler;
+ MockBIOSStringTable biosStringTable;
+
+ auto jsonIntegerReadWrite = R"({
+ "attribute_name" : "VDD_AVSBUS_RAIL",
+ "lower_bound" : 1,
+ "upper_bound" : 15,
+ "scalar_increment" : 1,
+ "default_value" : 2,
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus":{
+ "object_path" : "/xyz/openbmc_project/avsbus",
+ "interface" : "xyz.openbmc.AvsBus.Manager",
+ "property_type" : "uint8_t",
+ "property_name" : "Rail"
+ }
+ })"_json;
+ BIOSIntegerAttribute integerReadWrite{jsonIntegerReadWrite, &dbusHandler};
+ DBusMapping dbusMapping{"/xyz/openbmc_project/avsbus",
+ "xyz.openbmc.AvsBus.Manager", "Rail", "uint8_t"};
+ std::vector<uint8_t> attrValueEntry = {
+ 0, 0, /* attr handle */
+ 3, /* attr type integer read-write*/
+ 7, 0, 0, 0, 0, 0, 0, 0, /* current value */
+ };
+
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+ EXPECT_CALL(dbusHandler,
+ setDbusProperty(dbusMapping, PropertyValue{uint8_t(7)}))
+ .Times(1);
+ integerReadWrite.setAttrValueOnDbus(entry, nullptr, biosStringTable);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_string_attribute_test.cpp b/libpldmresponder/test/libpldmresponder_bios_string_attribute_test.cpp
new file mode 100644
index 0000000..d1c1703
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_string_attribute_test.cpp
@@ -0,0 +1,218 @@
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/bios_string_attribute.hpp"
+#include "mocked_bios.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm::responder::bios;
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Throw;
+
+class TestBIOSStringAttribute : public ::testing::Test
+{
+ public:
+ const auto& getStringInfo(const BIOSStringAttribute& biosStringAttribute)
+ {
+ return biosStringAttribute.stringInfo;
+ }
+};
+
+TEST_F(TestBIOSStringAttribute, CtorTest)
+{
+ auto jsonStringReadOnly = R"( {
+ "attribute_name" : "str_example3",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 2,
+ "default_string" : "ef",
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+ BIOSStringAttribute stringReadOnly{jsonStringReadOnly, nullptr};
+ EXPECT_EQ(stringReadOnly.name, "str_example3");
+ EXPECT_TRUE(stringReadOnly.readOnly);
+
+ auto& stringInfo = getStringInfo(stringReadOnly);
+ EXPECT_EQ(stringInfo.stringType,
+ static_cast<uint8_t>(BIOSStringAttribute::Encoding::ASCII));
+ EXPECT_EQ(stringInfo.minLength, 1);
+ EXPECT_EQ(stringInfo.maxLength, 100);
+ EXPECT_EQ(stringInfo.defLength, 2);
+ EXPECT_EQ(stringInfo.defString, "ef");
+
+ auto jsonStringReadOnlyError = R"( {
+ "attribute_name" : "str_example3",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string" : "ef",
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json; // missing default_string_length
+
+ EXPECT_THROW((BIOSStringAttribute{jsonStringReadOnlyError, nullptr}),
+ Json::exception);
+
+ auto jsonStringReadWrite = R"({
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example1.value",
+ "property_name" : "Str_example1",
+ "property_type" : "string"
+ }
+ })"_json;
+ BIOSStringAttribute stringReadWrite{jsonStringReadWrite, nullptr};
+
+ EXPECT_EQ(stringReadWrite.name, "str_example1");
+ EXPECT_TRUE(!stringReadWrite.readOnly);
+}
+
+TEST_F(TestBIOSStringAttribute, ConstructEntry)
+{
+ MockBIOSStringTable biosStringTable;
+ MockdBusHandler dbusHandler;
+
+ auto jsonStringReadOnly = R"({
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "readOnly" : true,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName"
+ })"_json;
+
+ std::vector<uint8_t> expectedAttrEntry{
+ 0, 0, /* attr handle */
+ 0x81, /* attr type string read-only */
+ 5, 0, /* attr name handle */
+ 1, /* string type */
+ 1, 0, /* minimum length of the string in bytes */
+ 100, 0, /* maximum length of the string in bytes */
+ 3, 0, /* length of default string in length */
+ 'a', 'b', 'c' /* default string */
+ };
+
+ std::vector<uint8_t> expectedAttrValueEntry{
+ 0, 0, /* attr handle */
+ 0x81, /* attr type string read-only */
+ 3, 0, /* current string length */
+ 'a', 'b', 'c', /* defaut value string handle index */
+ };
+
+ ON_CALL(biosStringTable, findHandle(StrEq("str_example1")))
+ .WillByDefault(Return(5));
+ BIOSStringAttribute stringReadOnly{jsonStringReadOnly, nullptr};
+
+ checkConstructEntry(stringReadOnly, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ auto jsonStringReadWrite = R"({
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example1.value",
+ "property_name" : "Str_example1",
+ "property_type" : "string"
+ }
+ })"_json;
+ BIOSStringAttribute stringReadWrite{jsonStringReadWrite, &dbusHandler};
+
+ /* Set expected attr type to read-write */
+ expectedAttrEntry[2] = PLDM_BIOS_STRING;
+ expectedAttrValueEntry[2] = PLDM_BIOS_STRING;
+
+ EXPECT_CALL(
+ dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/abc/def"), StrEq("Str_example1"),
+ StrEq("xyz.openbmc_project.str_example1.value")))
+ .WillOnce(Throw(std::exception()));
+
+ checkConstructEntry(stringReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+
+ EXPECT_CALL(
+ dbusHandler,
+ getDbusPropertyVariant(StrEq("/xyz/abc/def"), StrEq("Str_example1"),
+ StrEq("xyz.openbmc_project.str_example1.value")))
+ .WillOnce(Return(PropertyValue(std::string("abcd"))));
+
+ expectedAttrValueEntry = {
+ 0, 0, /* attr handle */
+ 1, /* attr type string read-write */
+ 4, 0, /* current string length */
+ 'a', 'b', 'c', 'd', /* defaut value string handle index */
+ };
+
+ checkConstructEntry(stringReadWrite, biosStringTable, expectedAttrEntry,
+ expectedAttrValueEntry);
+}
+
+TEST_F(TestBIOSStringAttribute, setAttrValueOnDbus)
+{
+ auto jsonStringReadWrite = R"({
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "readOnly" : false,
+ "helpText" : "HelpText",
+ "displayName" : "DisplayName",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example1.value",
+ "property_name" : "Str_example1",
+ "property_type" : "string"
+ }
+ })"_json;
+
+ MockdBusHandler dbusHandler;
+ MockBIOSStringTable biosStringTable;
+
+ BIOSStringAttribute stringReadWrite{jsonStringReadWrite, &dbusHandler};
+ DBusMapping dbusMapping{"/xyz/abc/def",
+ "xyz.openbmc_project.str_example1.value",
+ "Str_example1", "string"};
+ std::vector<uint8_t> attrValueEntry{
+ 0, 0, /* attr handle */
+ 1, /* attr type string read-write */
+ 4, 0, /* current string length */
+ 'a', 'b', 'c', 'd', /* defaut value string handle index */
+ };
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+ PropertyValue value = std::string("abcd");
+ EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1);
+ stringReadWrite.setAttrValueOnDbus(entry, nullptr, biosStringTable);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_table_test.cpp b/libpldmresponder/test/libpldmresponder_bios_table_test.cpp
new file mode 100644
index 0000000..47764ee
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_table_test.cpp
@@ -0,0 +1,61 @@
+#include "libpldmresponder/bios_table.hpp"
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder::bios;
+
+class TestBIOSTable : public testing::Test
+{
+ public:
+ void SetUp() override
+ {
+ char tmpdir[] = "/tmp/pldm_bios_table.XXXXXX";
+ dir = fs::path(mkdtemp(tmpdir));
+ }
+
+ void TearDown() override
+ {
+ fs::remove_all(dir);
+ }
+
+ fs::path dir;
+};
+
+TEST_F(TestBIOSTable, testStoreLoad)
+{
+ std::vector<uint8_t> table{10, 34, 56, 100, 44, 55, 69, 21, 48, 2, 7, 82};
+ fs::path file(dir / "t1");
+ BIOSTable t(file.string().c_str());
+ std::vector<uint8_t> out{};
+
+ ASSERT_THROW(t.load(out), fs::filesystem_error);
+
+ ASSERT_EQ(true, t.isEmpty());
+
+ t.store(table);
+ t.load(out);
+ ASSERT_EQ(true, std::equal(table.begin(), table.end(), out.begin()));
+}
+
+TEST_F(TestBIOSTable, testLoadOntoExisting)
+{
+ std::vector<uint8_t> table{10, 34, 56, 100, 44, 55, 69, 21, 48, 2, 7, 82};
+ fs::path file(dir / "t1");
+ BIOSTable t(file.string().c_str());
+ std::vector<uint8_t> out{99, 99};
+
+ ASSERT_THROW(t.load(out), fs::filesystem_error);
+
+ ASSERT_EQ(true, t.isEmpty());
+
+ t.store(table);
+ t.load(out);
+ ASSERT_EQ(true, std::equal(table.begin(), table.end(), out.begin() + 2));
+ ASSERT_EQ(out[0], 99);
+ ASSERT_EQ(out[1], 99);
+}
diff --git a/libpldmresponder/test/libpldmresponder_bios_test.cpp b/libpldmresponder/test/libpldmresponder_bios_test.cpp
new file mode 100644
index 0000000..9683d49
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_bios_test.cpp
@@ -0,0 +1,66 @@
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+
+#include "libpldmresponder/bios.hpp"
+#include "libpldmresponder/bios_table.hpp"
+
+#include <string.h>
+
+#include <array>
+#include <cstring>
+#include <ctime>
+#include <filesystem>
+
+#include <gtest/gtest.h>
+
+using namespace pldm;
+using namespace pldm::responder;
+using namespace pldm::responder::bios;
+using namespace pldm::responder::utils;
+
+TEST(epochToBCDTime, testTime)
+{
+ struct tm time
+ {};
+ time.tm_year = 119;
+ time.tm_mon = 3;
+ time.tm_mday = 13;
+ time.tm_hour = 5;
+ time.tm_min = 18;
+ time.tm_sec = 13;
+ time.tm_isdst = -1;
+
+ time_t epochTime = mktime(&time);
+ uint8_t seconds = 0;
+ uint8_t minutes = 0;
+ uint8_t hours = 0;
+ uint8_t day = 0;
+ uint8_t month = 0;
+ uint16_t year = 0;
+
+ epochToBCDTime(epochTime, seconds, minutes, hours, day, month, year);
+
+ ASSERT_EQ(0x13, seconds);
+ ASSERT_EQ(0x18, minutes);
+ ASSERT_EQ(0x5, hours);
+ ASSERT_EQ(0x13, day);
+ ASSERT_EQ(0x4, month);
+ ASSERT_EQ(0x2019, year);
+}
+
+TEST(timeToEpoch, testTime0)
+{
+ std::time_t ret = 1555132693;
+
+ uint8_t sec = 13;
+ uint8_t min = 18;
+ uint8_t hours = 5;
+ uint8_t day = 13;
+ uint8_t month = 4;
+ uint16_t year = 2019;
+
+ std::time_t timeSec = 0;
+ timeSec = timeToEpoch(sec, min, hours, day, month, year);
+
+ EXPECT_EQ(ret, timeSec);
+}
\ No newline at end of file
diff --git a/libpldmresponder/test/libpldmresponder_fru_test.cpp b/libpldmresponder/test/libpldmresponder_fru_test.cpp
new file mode 100644
index 0000000..7b1b470
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_fru_test.cpp
@@ -0,0 +1,64 @@
+#include "libpldmresponder/fru_parser.hpp"
+
+#include <gtest/gtest.h>
+TEST(FruParser, allScenarios)
+{
+ using namespace pldm::responder::fru_parser;
+
+ FruParser parser{"./fru_jsons/good"};
+
+ // Get an item with a single PLDM FRU record
+ FruRecordInfos cpu{
+ {1,
+ 1,
+ {{"xyz.openbmc_project.Inventory.Decorator.Asset", "Model", "string",
+ 2},
+ {"xyz.openbmc_project.Inventory.Decorator.Asset", "PartNumber",
+ "string", 3},
+ {"xyz.openbmc_project.Inventory.Decorator.Asset", "SerialNumber",
+ "string", 4},
+ {"xyz.openbmc_project.Inventory.Decorator.Asset", "Manufacturer",
+ "string", 5},
+ {"xyz.openbmc_project.Inventory.Item", "PrettyName", "string", 8},
+ {"xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
+ "string", 11},
+ {"xyz.openbmc_project.Inventory.Decorator.Revision", "Version",
+ "string", 10}}},
+ {1,
+ 1,
+ {{"xyz.openbmc_project.Inventory.Decorator.Asset", "PartNumber",
+ "string", 3},
+ {"xyz.openbmc_project.Inventory.Decorator.Asset", "SerialNumber",
+ "string", 4}}}};
+ auto cpuInfos =
+ parser.getRecordInfo("xyz.openbmc_project.Inventory.Item.Cpu");
+ ASSERT_EQ(cpuInfos.size(), 2);
+ ASSERT_EQ(cpu == cpuInfos, true);
+
+ // Get an item type with 3 PLDM FRU records
+ auto boardInfos =
+ parser.getRecordInfo("xyz.openbmc_project.Inventory.Item.Board");
+ ASSERT_EQ(boardInfos.size(), 3);
+
+ // D-Bus lookup info for FRU information
+ DBusLookupInfo lookupInfo{
+ "xyz.openbmc_project.Inventory.Manager",
+ "/xyz/openbmc_project/inventory",
+ {"xyz.openbmc_project.Inventory.Item.Chassis",
+ "xyz.openbmc_project.Inventory.Item.Board",
+ "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
+ "xyz.openbmc_project.Inventory.Item.Panel",
+ "xyz.openbmc_project.Inventory.Item.PowerSupply",
+ "xyz.openbmc_project.Inventory.Item.Vrm",
+ "xyz.openbmc_project.Inventory.Item.Cpu",
+ "xyz.openbmc_project.Inventory.Item.Bmc",
+ "xyz.openbmc_project.Inventory.Item.Dimm",
+ "xyz.openbmc_project.Inventory.Item.Tpm",
+ "xyz.openbmc_project.Inventory.Item.System"}};
+ auto dbusInfo = parser.inventoryLookup();
+ ASSERT_EQ(dbusInfo == lookupInfo, true);
+
+ ASSERT_THROW(
+ parser.getRecordInfo("xyz.openbmc_project.Inventory.Item.DIMM"),
+ std::exception);
+}
diff --git a/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp b/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp
new file mode 100644
index 0000000..4f3df87
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp
@@ -0,0 +1,215 @@
+#include "libpldm/platform.h"
+
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/pdr_utils.hpp"
+#include "libpldmresponder/platform.hpp"
+
+#include <sdbusplus/test/sdbus_mock.hpp>
+#include <sdeventplus/event.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder;
+using namespace pldm::responder::platform;
+using namespace pldm::responder::pdr;
+using namespace pldm::responder::pdr_utils;
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
+
+TEST(GeneratePDRByStateEffecter, testGoodJson)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
+
+ // 2 entries
+ ASSERT_EQ(outRepo.getRecordCount(), 2);
+
+ // Check first PDR
+ pdr_utils::PdrEntry e;
+ auto record2 = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record2, nullptr);
+ pldm_state_effecter_pdr* pdr =
+ reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
+
+ ASSERT_EQ(pdr->hdr.record_handle, 2);
+ ASSERT_EQ(pdr->hdr.version, 1);
+ ASSERT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
+ ASSERT_EQ(pdr->hdr.record_change_num, 0);
+ ASSERT_EQ(pdr->hdr.length, 23);
+
+ ASSERT_EQ(pdr->terminus_handle, BmcPldmTerminusHandle);
+ ASSERT_EQ(pdr->effecter_id, 1);
+ ASSERT_EQ(pdr->entity_type, 33);
+ ASSERT_EQ(pdr->entity_instance, 0);
+ ASSERT_EQ(pdr->container_id, 0);
+ ASSERT_EQ(pdr->effecter_semantic_id, 0);
+ ASSERT_EQ(pdr->effecter_init, PLDM_NO_INIT);
+ ASSERT_EQ(pdr->has_description_pdr, false);
+ ASSERT_EQ(pdr->composite_effecter_count, 2);
+ state_effecter_possible_states* states =
+ reinterpret_cast<state_effecter_possible_states*>(pdr->possible_states);
+ ASSERT_EQ(states->state_set_id, 196);
+ ASSERT_EQ(states->possible_states_size, 1);
+ bitfield8_t bf1{};
+ bf1.byte = 2;
+ ASSERT_EQ(states->states[0].byte, bf1.byte);
+
+ const auto& [dbusMappings1, dbusValMaps1] =
+ handler.getDbusObjMaps(pdr->effecter_id);
+ ASSERT_EQ(dbusMappings1[0].objectPath, "/foo/bar");
+
+ // Check second PDR
+ auto record3 = pdr::getRecordByHandle(outRepo, 3, e);
+ ASSERT_NE(record3, nullptr);
+ pdr = reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
+
+ ASSERT_EQ(pdr->hdr.record_handle, 3);
+ ASSERT_EQ(pdr->hdr.version, 1);
+ ASSERT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
+ ASSERT_EQ(pdr->hdr.record_change_num, 0);
+ ASSERT_EQ(pdr->hdr.length, 24);
+
+ ASSERT_EQ(pdr->terminus_handle, BmcPldmTerminusHandle);
+ ASSERT_EQ(pdr->effecter_id, 2);
+ ASSERT_EQ(pdr->entity_type, 100);
+ ASSERT_EQ(pdr->entity_instance, 0);
+ ASSERT_EQ(pdr->container_id, 0);
+ ASSERT_EQ(pdr->effecter_semantic_id, 0);
+ ASSERT_EQ(pdr->effecter_init, PLDM_NO_INIT);
+ ASSERT_EQ(pdr->has_description_pdr, false);
+ ASSERT_EQ(pdr->composite_effecter_count, 2);
+ states =
+ reinterpret_cast<state_effecter_possible_states*>(pdr->possible_states);
+ ASSERT_EQ(states->state_set_id, 197);
+ ASSERT_EQ(states->possible_states_size, 1);
+ bf1.byte = 2;
+ ASSERT_EQ(states->states[0].byte, bf1.byte);
+ states = reinterpret_cast<state_effecter_possible_states*>(
+ pdr->possible_states + sizeof(state_effecter_possible_states));
+ ASSERT_EQ(states->state_set_id, 198);
+ ASSERT_EQ(states->possible_states_size, 2);
+ bitfield8_t bf2[2];
+ bf2[0].byte = 38;
+ bf2[1].byte = 128;
+ ASSERT_EQ(states->states[0].byte, bf2[0].byte);
+ ASSERT_EQ(states->states[1].byte, bf2[1].byte);
+
+ const auto& [dbusMappings2, dbusValMaps2] =
+ handler.getDbusObjMaps(pdr->effecter_id);
+ ASSERT_EQ(dbusMappings2[0].objectPath, "/foo/bar");
+ ASSERT_EQ(dbusMappings2[1].objectPath, "/foo/bar");
+
+ ASSERT_THROW(handler.getDbusObjMaps(0xDEAD), std::exception);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(GeneratePDRByNumericEffecter, testGoodJson)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_NUMERIC_EFFECTER_PDR);
+
+ // 1 entries
+ ASSERT_EQ(outRepo.getRecordCount(), 1);
+
+ // Check first PDR
+ pdr_utils::PdrEntry e;
+ auto record = pdr::getRecordByHandle(outRepo, 4, e);
+ ASSERT_NE(record, nullptr);
+
+ pldm_numeric_effecter_value_pdr* pdr =
+ reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.record_handle, 4);
+ EXPECT_EQ(pdr->hdr.version, 1);
+ EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
+ EXPECT_EQ(pdr->hdr.record_change_num, 0);
+ EXPECT_EQ(pdr->hdr.length,
+ sizeof(pldm_numeric_effecter_value_pdr) - sizeof(pldm_pdr_hdr));
+
+ EXPECT_EQ(pdr->effecter_id, 3);
+ EXPECT_EQ(pdr->effecter_data_size, 4);
+
+ const auto& [dbusMappings, dbusValMaps] =
+ handler.getDbusObjMaps(pdr->effecter_id);
+ EXPECT_EQ(dbusMappings[0].objectPath, "/foo/bar");
+ EXPECT_EQ(dbusMappings[0].interface, "xyz.openbmc_project.Foo.Bar");
+ EXPECT_EQ(dbusMappings[0].propertyName, "propertyName");
+ EXPECT_EQ(dbusMappings[0].propertyType, "uint64_t");
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(GeneratePDR, testMalformedJson)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
+
+ ASSERT_EQ(outRepo.getRecordCount(), 2);
+ ASSERT_THROW(pdr_utils::readJson("./pdr_jsons/state_effecter/malformed"),
+ std::exception);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(findStateEffecterId, goodJson)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ uint16_t entityType = 33;
+ uint16_t entityInstance = 0;
+ uint16_t containerId = 0;
+ uint16_t stateSetId = 196;
+ auto effecterId = findStateEffecterId(inPDRRepo, entityType, entityInstance,
+ containerId, stateSetId, true);
+ ASSERT_EQ(effecterId, 1);
+ stateSetId = 300;
+ effecterId = findStateEffecterId(inPDRRepo, entityType, entityInstance,
+ containerId, stateSetId, true);
+ ASSERT_EQ(effecterId, PLDM_INVALID_EFFECTER_ID);
+ pldm_pdr_destroy(inPDRRepo);
+}
diff --git a/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp b/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp
new file mode 100644
index 0000000..f95df0c
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp
@@ -0,0 +1,100 @@
+#include "libpldm/platform.h"
+
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/pdr_utils.hpp"
+#include "libpldmresponder/platform.hpp"
+
+#include <sdbusplus/test/sdbus_mock.hpp>
+#include <sdeventplus/event.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace pldm::responder;
+using namespace pldm::responder::platform;
+using namespace pldm::responder::pdr;
+using namespace pldm::responder::pdr_utils;
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
+
+TEST(GeneratePDRByStateSensor, testGoodJson)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(1)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_sensor/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ handler.getPDR(req, requestPayloadLength);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
+
+ // 1 entries
+ ASSERT_EQ(outRepo.getRecordCount(), 1);
+
+ // Check first PDR
+ pdr_utils::PdrEntry e;
+ auto record = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record, nullptr);
+
+ pldm_state_sensor_pdr* pdr =
+ reinterpret_cast<pldm_state_sensor_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.record_handle, 2);
+ EXPECT_EQ(pdr->hdr.version, 1);
+ EXPECT_EQ(pdr->hdr.type, PLDM_STATE_SENSOR_PDR);
+ EXPECT_EQ(pdr->hdr.record_change_num, 0);
+ EXPECT_EQ(pdr->hdr.length, 17);
+
+ EXPECT_EQ(pdr->sensor_id, 1);
+
+ const auto& [dbusMappings, dbusValMaps] =
+ handler.getDbusObjMaps(pdr->sensor_id, TypeId::PLDM_SENSOR_ID);
+ ASSERT_EQ(dbusMappings[0].objectPath, "/foo/bar");
+ ASSERT_EQ(dbusMappings[0].interface, "xyz.openbmc_project.Foo.Bar");
+ ASSERT_EQ(dbusMappings[0].propertyName, "propertyName");
+ ASSERT_EQ(dbusMappings[0].propertyType, "string");
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(GeneratePDR, testMalformedJson)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(1)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_sensor/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ handler.getPDR(req, requestPayloadLength);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
+
+ ASSERT_EQ(outRepo.getRecordCount(), 1);
+ ASSERT_THROW(pdr_utils::readJson("./pdr_jsons/state_sensor/malformed"),
+ std::exception);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
diff --git a/libpldmresponder/test/libpldmresponder_platform_test.cpp b/libpldmresponder/test/libpldmresponder_platform_test.cpp
new file mode 100644
index 0000000..b8fe603
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_platform_test.cpp
@@ -0,0 +1,664 @@
+#include "common/test/mocked_utils.hpp"
+#include "common/utils.hpp"
+#include "libpldmresponder/event_parser.hpp"
+#include "libpldmresponder/pdr.hpp"
+#include "libpldmresponder/pdr_utils.hpp"
+#include "libpldmresponder/platform.hpp"
+#include "libpldmresponder/platform_numeric_effecter.hpp"
+#include "libpldmresponder/platform_state_effecter.hpp"
+#include "libpldmresponder/platform_state_sensor.hpp"
+
+#include <sdbusplus/test/sdbus_mock.hpp>
+#include <sdeventplus/event.hpp>
+
+#include <iostream>
+
+using namespace pldm::utils;
+using namespace pldm::responder;
+using namespace pldm::responder::platform;
+using namespace pldm::responder::pdr;
+using namespace pldm::responder::pdr_utils;
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
+
+TEST(getPDR, testGoodPath)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ struct pldm_get_pdr_req* request =
+ reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+ request->request_count = 100;
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto pdrRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", pdrRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo repo(pdrRepo);
+ ASSERT_EQ(repo.empty(), false);
+ auto response = handler.getPDR(req, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ struct pldm_get_pdr_resp* resp =
+ reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
+ ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
+ ASSERT_EQ(2, resp->next_record_handle);
+ ASSERT_EQ(true, resp->response_count != 0);
+
+ pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(resp->record_data);
+ ASSERT_EQ(hdr->record_handle, 1);
+ ASSERT_EQ(hdr->version, 1);
+
+ pldm_pdr_destroy(pdrRepo);
+}
+
+TEST(getPDR, testShortRead)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ struct pldm_get_pdr_req* request =
+ reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+ request->request_count = 1;
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto pdrRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", pdrRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo repo(pdrRepo);
+ ASSERT_EQ(repo.empty(), false);
+ auto response = handler.getPDR(req, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_get_pdr_resp* resp =
+ reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
+ ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
+ ASSERT_EQ(1, resp->response_count);
+ pldm_pdr_destroy(pdrRepo);
+}
+
+TEST(getPDR, testBadRecordHandle)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ struct pldm_get_pdr_req* request =
+ reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+ request->record_handle = 100000;
+ request->request_count = 1;
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto pdrRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", pdrRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo repo(pdrRepo);
+ ASSERT_EQ(repo.empty(), false);
+ auto response = handler.getPDR(req, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ ASSERT_EQ(responsePtr->payload[0], PLDM_PLATFORM_INVALID_RECORD_HANDLE);
+
+ pldm_pdr_destroy(pdrRepo);
+}
+
+TEST(getPDR, testNoNextRecord)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ struct pldm_get_pdr_req* request =
+ reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+ request->record_handle = 1;
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto pdrRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", pdrRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo repo(pdrRepo);
+ ASSERT_EQ(repo.empty(), false);
+ auto response = handler.getPDR(req, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_get_pdr_resp* resp =
+ reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
+ ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
+ ASSERT_EQ(2, resp->next_record_handle);
+
+ pldm_pdr_destroy(pdrRepo);
+}
+
+TEST(getPDR, testFindPDR)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ struct pldm_get_pdr_req* request =
+ reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+ request->request_count = 100;
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto pdrRepo = pldm_pdr_init();
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", pdrRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo repo(pdrRepo);
+ ASSERT_EQ(repo.empty(), false);
+ auto response = handler.getPDR(req, requestPayloadLength);
+
+ // Let's try to find a PDR of type stateEffecter (= 11) and entity type =
+ // 100
+ bool found = false;
+ uint32_t handle = 0; // start asking for PDRs from recordHandle 0
+ while (!found)
+ {
+ request->record_handle = handle;
+ auto response = handler.getPDR(req, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_get_pdr_resp* resp =
+ reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
+ ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
+
+ handle = resp->next_record_handle; // point to the next pdr in case
+ // current is not what we want
+
+ pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(resp->record_data);
+ std::cerr << "PDR next record handle " << handle << "\n";
+ std::cerr << "PDR type " << hdr->type << "\n";
+ if (hdr->type == PLDM_STATE_EFFECTER_PDR)
+ {
+ pldm_state_effecter_pdr* pdr =
+ reinterpret_cast<pldm_state_effecter_pdr*>(resp->record_data);
+ std::cerr << "PDR entity type " << pdr->entity_type << "\n";
+ if (pdr->entity_type == 100)
+ {
+ found = true;
+ // Rest of the PDR can be accessed as need be
+ break;
+ }
+ }
+ if (!resp->next_record_handle) // no more records
+ {
+ break;
+ }
+ }
+ ASSERT_EQ(found, true);
+
+ pldm_pdr_destroy(pdrRepo);
+}
+
+TEST(setStateEffecterStatesHandler, testGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ handler.getPDR(req, requestPayloadLength);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
+ pdr_utils::PdrEntry e;
+ auto record1 = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record1, nullptr);
+ pldm_state_effecter_pdr* pdr =
+ reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
+
+ std::vector<set_effecter_state_field> stateField;
+ stateField.push_back({PLDM_REQUEST_SET, 1});
+ stateField.push_back({PLDM_REQUEST_SET, 1});
+ std::string value = "xyz.openbmc_project.Foo.Bar.V1";
+ PropertyValue propertyValue = value;
+
+ DBusMapping dbusMapping{"/foo/bar", "xyz.openbmc_project.Foo.Bar",
+ "propertyName", "string"};
+
+ EXPECT_CALL(mockedUtils, setDbusProperty(dbusMapping, propertyValue))
+ .Times(2);
+ auto rc = platform_state_effecter::setStateEffecterStatesHandler<
+ MockdBusHandler, Handler>(mockedUtils, handler, 0x1, stateField);
+ ASSERT_EQ(rc, 0);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(setStateEffecterStatesHandler, testBadRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
+ requestPayload{};
+ auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ handler.getPDR(req, requestPayloadLength);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
+ pdr_utils::PdrEntry e;
+ auto record1 = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record1, nullptr);
+ pldm_state_effecter_pdr* pdr =
+ reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
+
+ std::vector<set_effecter_state_field> stateField;
+ stateField.push_back({PLDM_REQUEST_SET, 3});
+ stateField.push_back({PLDM_REQUEST_SET, 4});
+
+ auto rc = platform_state_effecter::setStateEffecterStatesHandler<
+ MockdBusHandler, Handler>(mockedUtils, handler, 0x1, stateField);
+ ASSERT_EQ(rc, PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE);
+
+ rc = platform_state_effecter::setStateEffecterStatesHandler<MockdBusHandler,
+ Handler>(
+ mockedUtils, handler, 0x9, stateField);
+ ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_EFFECTER_ID);
+
+ stateField.push_back({PLDM_REQUEST_SET, 4});
+ rc = platform_state_effecter::setStateEffecterStatesHandler<MockdBusHandler,
+ Handler>(
+ mockedUtils, handler, 0x1, stateField);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(setNumericEffecterValueHandler, testGoodRequest)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto numericEffecterPdrRepo = pldm_pdr_init();
+ Repo numericEffecterPDRs(numericEffecterPdrRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
+
+ pdr_utils::PdrEntry e;
+ auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
+ ASSERT_NE(record4, nullptr);
+
+ pldm_numeric_effecter_value_pdr* pdr =
+ reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
+
+ uint16_t effecterId = 3;
+ uint32_t effecterValue = 2100000000; // 2036-07-18 21:20:00
+ PropertyValue propertyValue = static_cast<uint32_t>(effecterValue);
+
+ DBusMapping dbusMapping{"/foo/bar", "xyz.openbmc_project.Foo.Bar",
+ "propertyName", "uint64_t"};
+ EXPECT_CALL(mockedUtils, setDbusProperty(dbusMapping, propertyValue))
+ .Times(1);
+
+ auto rc = platform_numeric_effecter::setNumericEffecterValueHandler<
+ MockdBusHandler, Handler>(
+ mockedUtils, handler, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
+ reinterpret_cast<uint8_t*>(&effecterValue), 4);
+ ASSERT_EQ(rc, 0);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(numericEffecterPdrRepo);
+}
+
+TEST(setNumericEffecterValueHandler, testBadRequest)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(5)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto numericEffecterPdrRepo = pldm_pdr_init();
+ Repo numericEffecterPDRs(numericEffecterPdrRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_effecter/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
+
+ pdr_utils::PdrEntry e;
+ auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
+ ASSERT_NE(record4, nullptr);
+
+ pldm_numeric_effecter_value_pdr* pdr =
+ reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
+
+ uint16_t effecterId = 3;
+ uint64_t effecterValue = 9876543210;
+ auto rc = platform_numeric_effecter::setNumericEffecterValueHandler<
+ MockdBusHandler, Handler>(
+ mockedUtils, handler, effecterId, PLDM_EFFECTER_DATA_SIZE_SINT32,
+ reinterpret_cast<uint8_t*>(&effecterValue), 3);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(numericEffecterPdrRepo);
+}
+
+TEST(parseStateSensor, allScenarios)
+{
+ // Sample state sensor with SensorID - 1, EntityType - Processor Module(67)
+ // State Set ID - Operational Running Status(11), Supported States - 3,4
+ std::vector<uint8_t> sample1PDR{0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x0b, 0x00, 0x01, 0x18};
+
+ const auto& [terminusHandle1, sensorID1, sensorInfo1] =
+ parseStateSensorPDR(sample1PDR);
+ const auto& [containerID1, entityType1, entityInstance1] =
+ std::get<0>(sensorInfo1);
+ const auto& states1 = std::get<1>(sensorInfo1);
+ CompositeSensorStates statesCmp1{{3u, 4u}};
+
+ ASSERT_EQ(le16toh(terminusHandle1), 0u);
+ ASSERT_EQ(le16toh(sensorID1), 1u);
+ ASSERT_EQ(le16toh(containerID1), 0u);
+ ASSERT_EQ(le16toh(entityType1), 67u);
+ ASSERT_EQ(le16toh(entityInstance1), 1u);
+ ASSERT_EQ(states1, statesCmp1);
+
+ // Sample state sensor with SensorID - 2, EntityType - System Firmware(31)
+ // State Set ID - Availability(2), Supported States - 3,4,9,10,11,13
+ std::vector<uint8_t> sample2PDR{0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x1F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x00, 0x02, 0x18, 0x2E};
+
+ const auto& [terminusHandle2, sensorID2, sensorInfo2] =
+ parseStateSensorPDR(sample2PDR);
+ const auto& [containerID2, entityType2, entityInstance2] =
+ std::get<0>(sensorInfo2);
+ const auto& states2 = std::get<1>(sensorInfo2);
+ CompositeSensorStates statesCmp2{{3u, 4u, 9u, 10u, 11u, 13u}};
+
+ ASSERT_EQ(le16toh(terminusHandle2), 0u);
+ ASSERT_EQ(le16toh(sensorID2), 2u);
+ ASSERT_EQ(le16toh(containerID2), 0u);
+ ASSERT_EQ(le16toh(entityType2), 31u);
+ ASSERT_EQ(le16toh(entityInstance2), 1u);
+ ASSERT_EQ(states2, statesCmp2);
+
+ // Sample state sensor with SensorID - 3, EntityType - Virtual Machine
+ // Manager(33), Composite State Sensor -2 , State Set ID - Link State(33),
+ // Supported States - 1,2, State Set ID - Configuration State(15),
+ // Supported States - 1,2,3,4
+ std::vector<uint8_t> sample3PDR{
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x17, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x21, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x21, 0x00, 0x01, 0x06, 0x0F, 0x00, 0x01, 0x1E};
+
+ const auto& [terminusHandle3, sensorID3, sensorInfo3] =
+ parseStateSensorPDR(sample3PDR);
+ const auto& [containerID3, entityType3, entityInstance3] =
+ std::get<0>(sensorInfo3);
+ const auto& states3 = std::get<1>(sensorInfo3);
+ CompositeSensorStates statesCmp3{{1u, 2u}, {1u, 2u, 3u, 4u}};
+
+ ASSERT_EQ(le16toh(terminusHandle3), 0u);
+ ASSERT_EQ(le16toh(sensorID3), 3u);
+ ASSERT_EQ(le16toh(containerID3), 1u);
+ ASSERT_EQ(le16toh(entityType3), 33u);
+ ASSERT_EQ(le16toh(entityInstance3), 2u);
+ ASSERT_EQ(states3, statesCmp3);
+}
+
+TEST(StateSensorHandler, allScenarios)
+{
+ using namespace pldm::responder::events;
+
+ StateSensorHandler handler{"./event_jsons/good"};
+ constexpr uint8_t eventState0 = 0;
+ constexpr uint8_t eventState1 = 1;
+ constexpr uint8_t eventState2 = 2;
+ constexpr uint8_t eventState3 = 3;
+
+ // Event Entry 1
+ {
+ StateSensorEntry entry{1, 64, 1, 0};
+ const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+ DBusMapping mapping{"/xyz/abc/def",
+ "xyz.openbmc_project.example1.value", "value1",
+ "string"};
+ ASSERT_EQ(mapping == dbusMapping, true);
+
+ const auto& propValue0 = eventStateMap.at(eventState0);
+ const auto& propValue1 = eventStateMap.at(eventState1);
+ const auto& propValue2 = eventStateMap.at(eventState2);
+ PropertyValue value0{std::in_place_type<std::string>,
+ "xyz.openbmc_project.State.Normal"};
+ PropertyValue value1{std::in_place_type<std::string>,
+ "xyz.openbmc_project.State.Critical"};
+ PropertyValue value2{std::in_place_type<std::string>,
+ "xyz.openbmc_project.State.Fatal"};
+ ASSERT_EQ(value0 == propValue0, true);
+ ASSERT_EQ(value1 == propValue1, true);
+ ASSERT_EQ(value2 == propValue2, true);
+ }
+
+ // Event Entry 2
+ {
+ StateSensorEntry entry{1, 64, 1, 1};
+ const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+ DBusMapping mapping{"/xyz/abc/def",
+ "xyz.openbmc_project.example2.value", "value2",
+ "uint8_t"};
+ ASSERT_EQ(mapping == dbusMapping, true);
+
+ const auto& propValue0 = eventStateMap.at(eventState2);
+ const auto& propValue1 = eventStateMap.at(eventState3);
+ PropertyValue value0{std::in_place_type<uint8_t>, 9};
+ PropertyValue value1{std::in_place_type<uint8_t>, 10};
+ ASSERT_EQ(value0 == propValue0, true);
+ ASSERT_EQ(value1 == propValue1, true);
+ }
+
+ // Event Entry 3
+ {
+ StateSensorEntry entry{2, 67, 2, 0};
+ const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+ DBusMapping mapping{"/xyz/abc/ghi",
+ "xyz.openbmc_project.example3.value", "value3",
+ "bool"};
+ ASSERT_EQ(mapping == dbusMapping, true);
+
+ const auto& propValue0 = eventStateMap.at(eventState0);
+ const auto& propValue1 = eventStateMap.at(eventState1);
+ PropertyValue value0{std::in_place_type<bool>, false};
+ PropertyValue value1{std::in_place_type<bool>, true};
+ ASSERT_EQ(value0 == propValue0, true);
+ ASSERT_EQ(value1 == propValue1, true);
+ }
+
+ // Invalid Entry
+ {
+ StateSensorEntry entry{0, 0, 0, 0};
+ ASSERT_THROW(handler.getEventInfo(entry), std::out_of_range);
+ }
+}
+
+TEST(TerminusLocatorPDR, BMCTerminusLocatorPDR)
+{
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ MockdBusHandler mockedUtils;
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "", inPDRRepo, nullptr, nullptr, nullptr,
+ nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_TERMINUS_LOCATOR_PDR);
+
+ // 1 BMC terminus locator PDR in the PDR repository
+ ASSERT_EQ(outRepo.getRecordCount(), 1);
+
+ pdr_utils::PdrEntry entry;
+ auto record = pdr::getRecordByHandle(outRepo, 1, entry);
+ ASSERT_NE(record, nullptr);
+
+ auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(entry.data);
+ EXPECT_EQ(pdr->hdr.record_handle, 1);
+ EXPECT_EQ(pdr->hdr.version, 1);
+ EXPECT_EQ(pdr->hdr.type, PLDM_TERMINUS_LOCATOR_PDR);
+ EXPECT_EQ(pdr->hdr.record_change_num, 0);
+ EXPECT_EQ(pdr->hdr.length,
+ sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr));
+ EXPECT_EQ(pdr->terminus_handle, BmcPldmTerminusHandle);
+ EXPECT_EQ(pdr->validity, PLDM_TL_PDR_VALID);
+ EXPECT_EQ(pdr->tid, BmcTerminusId);
+ EXPECT_EQ(pdr->container_id, 0);
+ EXPECT_EQ(pdr->terminus_locator_type, PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID);
+ EXPECT_EQ(pdr->terminus_locator_value_size,
+ sizeof(pldm_terminus_locator_type_mctp_eid));
+ auto locatorValue =
+ reinterpret_cast<const pldm_terminus_locator_type_mctp_eid*>(
+ pdr->terminus_locator_value);
+ EXPECT_EQ(locatorValue->eid, BmcMctpEid);
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(getStateSensorReadingsHandler, testGoodRequest)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(1)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_sensor/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
+ pdr_utils::PdrEntry e;
+ auto record = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record, nullptr);
+ pldm_state_sensor_pdr* pdr =
+ reinterpret_cast<pldm_state_sensor_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_STATE_SENSOR_PDR);
+
+ std::vector<get_sensor_state_field> stateField;
+ uint8_t compSensorCnt{};
+ uint8_t sensorRearmCnt = 1;
+
+ MockdBusHandler handlerObj;
+ EXPECT_CALL(handlerObj,
+ getDbusPropertyVariant(StrEq("/foo/bar"), StrEq("propertyName"),
+ StrEq("xyz.openbmc_project.Foo.Bar")))
+ .WillOnce(Return(
+ PropertyValue(std::string("xyz.openbmc_project.Foo.Bar.V0"))));
+
+ auto rc = platform_state_sensor::getStateSensorReadingsHandler<
+ MockdBusHandler, Handler>(handlerObj, handler, 0x1, sensorRearmCnt,
+ compSensorCnt, stateField);
+ ASSERT_EQ(rc, 0);
+ ASSERT_EQ(compSensorCnt, 1);
+ ASSERT_EQ(stateField[0].sensor_op_state, PLDM_SENSOR_UNAVAILABLE);
+ ASSERT_EQ(stateField[0].present_state, PLDM_SENSOR_NORMAL);
+ ASSERT_EQ(stateField[0].previous_state, PLDM_SENSOR_UNKNOWN);
+ ASSERT_EQ(stateField[0].event_state, PLDM_SENSOR_UNKNOWN);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
+
+TEST(getStateSensorReadingsHandler, testBadRequest)
+{
+ MockdBusHandler mockedUtils;
+ EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
+ .Times(1)
+ .WillRepeatedly(Return("foo.bar"));
+
+ auto inPDRRepo = pldm_pdr_init();
+ auto outPDRRepo = pldm_pdr_init();
+ Repo outRepo(outPDRRepo);
+ auto event = sdeventplus::Event::get_default();
+ Handler handler(&mockedUtils, "./pdr_jsons/state_sensor/good", inPDRRepo,
+ nullptr, nullptr, nullptr, nullptr, event);
+ Repo inRepo(inPDRRepo);
+ getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
+ pdr_utils::PdrEntry e;
+ auto record = pdr::getRecordByHandle(outRepo, 2, e);
+ ASSERT_NE(record, nullptr);
+ pldm_state_sensor_pdr* pdr =
+ reinterpret_cast<pldm_state_sensor_pdr*>(e.data);
+ EXPECT_EQ(pdr->hdr.type, PLDM_STATE_SENSOR_PDR);
+
+ std::vector<get_sensor_state_field> stateField;
+ uint8_t compSensorCnt{};
+ uint8_t sensorRearmCnt = 3;
+
+ MockdBusHandler handlerObj;
+ auto rc = platform_state_sensor::getStateSensorReadingsHandler<
+ MockdBusHandler, Handler>(handlerObj, handler, 0x1, sensorRearmCnt,
+ compSensorCnt, stateField);
+ ASSERT_EQ(rc, PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE);
+
+ pldm_pdr_destroy(inPDRRepo);
+ pldm_pdr_destroy(outPDRRepo);
+}
diff --git a/libpldmresponder/test/meson.build b/libpldmresponder/test/meson.build
new file mode 100644
index 0000000..623e28e
--- /dev/null
+++ b/libpldmresponder/test/meson.build
@@ -0,0 +1,46 @@
+tests = [
+ 'libpldmresponder_base_test',
+ 'libpldmresponder_bios_test',
+ 'libpldmresponder_bios_attribute_test',
+ 'libpldmresponder_bios_config_test',
+ 'libpldmresponder_bios_enum_attribute_test',
+ 'libpldmresponder_bios_integer_attribute_test',
+ 'libpldmresponder_bios_string_attribute_test',
+ 'libpldmresponder_bios_table_test',
+ 'libpldmresponder_fru_test',
+ 'libpldmresponder_platform_test',
+ 'libpldmresponder_pdr_effecter_test',
+ 'libpldmresponder_pdr_sensor_test',
+]
+
+if get_option('oem-ibm').enabled()
+ tests += [
+ '../../oem/ibm/test/libpldmresponder_fileio_test',
+ '../../oem/ibm/test/libpldmresponder_oem_platform_test'
+ ]
+endif
+
+ dep_src_files = [
+ '../../pldmd/instance_id.cpp',
+ '../../pldmd/dbus_impl_requester.cpp'
+ ]
+dep_src = declare_dependency(sources: dep_src_files)
+
+foreach t : tests
+ test(t, executable(t.underscorify(), t + '.cpp',
+ implicit_include_directories: false,
+ link_args: dynamic_linker,
+ build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
+ dependencies: [
+ dep_src,
+ libpldm_dep,
+ libpldmresponder,
+ libpldmutils,
+ gtest,
+ gmock,
+ nlohmann_json,
+ phosphor_dbus_interfaces,
+ sdeventplus,
+ sdbusplus]),
+ workdir: meson.current_source_dir())
+endforeach
diff --git a/libpldmresponder/test/mocked_bios.hpp b/libpldmresponder/test/mocked_bios.hpp
new file mode 100644
index 0000000..6741306
--- /dev/null
+++ b/libpldmresponder/test/mocked_bios.hpp
@@ -0,0 +1,58 @@
+#include "libpldmresponder/bios_table.hpp"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::ElementsAreArray;
+using namespace pldm::responder::bios;
+
+class MockBIOSStringTable : public BIOSStringTable
+{
+ public:
+ MockBIOSStringTable() : BIOSStringTable({})
+ {}
+
+ MOCK_METHOD(uint16_t, findHandle, (const std::string&), (const override));
+
+ MOCK_METHOD(std::string, findString, (const uint16_t), (const override));
+};
+
+void checkHeader(const Table& attrEntry, const Table& attrValueEntry)
+{
+ auto attrHeader = table::attribute::decodeHeader(
+ reinterpret_cast<const pldm_bios_attr_table_entry*>(attrEntry.data()));
+ auto attrValueHeader = table::attribute_value::decodeHeader(
+ reinterpret_cast<const pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data()));
+
+ EXPECT_EQ(attrHeader.attrHandle, attrValueHeader.attrHandle);
+}
+
+void checkEntry(Table& entry, Table& expectedEntry)
+{
+ /** backup the attr handle */
+ auto attr0 = entry[0], eAttr0 = expectedEntry[0];
+ auto attr1 = entry[1], eAttr1 = expectedEntry[1];
+
+ /** attr handle is computed by libpldm, set it to 0 to test */
+ entry[0] = 0, expectedEntry[0] = 0;
+ entry[1] = 0, expectedEntry[1] = 0;
+
+ EXPECT_THAT(entry, ElementsAreArray(expectedEntry));
+
+ /** restore the attr handle */
+ entry[0] = attr0, expectedEntry[0] = eAttr0;
+ entry[1] = attr1, expectedEntry[1] = eAttr1;
+}
+
+void checkConstructEntry(BIOSAttribute& attribute, BIOSStringTable& stringTable,
+ Table& expectedAttrEntry,
+ Table& expectedAttrValueEntry)
+{
+ Table attrEntry, attrValueEntry;
+ attribute.constructEntry(stringTable, attrEntry, attrValueEntry);
+
+ checkHeader(attrEntry, attrValueEntry);
+ checkEntry(attrEntry, expectedAttrEntry);
+ checkEntry(attrValueEntry, expectedAttrValueEntry);
+}
\ No newline at end of file
diff --git a/libpldmresponder/test/pdr_jsons/state_effecter/good/effecter_pdr.json b/libpldmresponder/test/pdr_jsons/state_effecter/good/effecter_pdr.json
new file mode 100644
index 0000000..1514a59
--- /dev/null
+++ b/libpldmresponder/test/pdr_jsons/state_effecter/good/effecter_pdr.json
@@ -0,0 +1,127 @@
+{
+ "effecterPDRs": [
+ {
+ "pdrType": 11,
+ "entries": [
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 33,
+ "instance": 0,
+ "container": 0,
+ "effecters": [
+ {
+ "set": {
+ "id": 196,
+ "size": 1,
+ "states": [
+ 1
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1"
+ ]
+ }
+ },
+ {
+ "set": {
+ "id": 196,
+ "size": 1,
+ "states": [
+ 1,
+ 2
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1",
+ "xyz.openbmc_project.Foo.Bar.V2"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 100,
+ "instance": 0,
+ "container": 0,
+ "effecters": [
+ {
+ "set": {
+ "id": 197,
+ "size": 1,
+ "states": [
+ 1
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1"
+ ]
+ }
+ },
+ {
+ "set": {
+ "id": 198,
+ "size": 2,
+ "states": [
+ 1,
+ 2,
+ 5,
+ 15
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar.Baz",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.Baz.V1",
+ "xyz.openbmc_project.Foo.Bar.Baz.V2",
+ "xyz.openbmc_project.Foo.Bar.Baz.V5",
+ "xyz.openbmc_project.Foo.Bar.Baz.V15"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "pdrType": 9,
+ "entries": [
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 0,
+ "instance": 0,
+ "container": 0,
+ "base_unit": 21,
+ "rate_unit": 3,
+ "effecter_resolution_init": 1,
+ "effecter_data_size": 4,
+ "range_field_format": 4,
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "uint64_t"
+ }
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libpldmresponder/test/pdr_jsons/state_effecter/malformed/effecter_pdr.json b/libpldmresponder/test/pdr_jsons/state_effecter/malformed/effecter_pdr.json
new file mode 100644
index 0000000..826e27a
--- /dev/null
+++ b/libpldmresponder/test/pdr_jsons/state_effecter/malformed/effecter_pdr.json
@@ -0,0 +1,127 @@
+{
+ "effecterPDRs": [
+ {
+ "pdrType": 11,
+ "entries": [
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 33
+ "instance": 0,
+ "container": 0,
+ "effecters": [
+ {
+ "set": {
+ "id": 196,
+ "size": 1,
+ "states": [
+ 1
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1"
+ ]
+ }
+ },
+ {
+ "set": {
+ "id": 196,
+ "size": 1,
+ "states": [
+ 1,
+ 2
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1",
+ "xyz.openbmc_project.Foo.Bar.V2"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 100,
+ "instance": 0,
+ "container": 0,
+ "effecters": [
+ {
+ "set": {
+ "id": 197,
+ "size": 1,
+ "states": [
+ 1
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V1"
+ ]
+ }
+ },
+ {
+ "set": {
+ "id": 198,
+ "size": 2,
+ "states": [
+ 1,
+ 2,
+ 5,
+ 15
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar.Baz",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.Baz.V1",
+ "xyz.openbmc_project.Foo.Bar.Baz.V2",
+ "xyz.openbmc_project.Foo.Bar.Baz.V5",
+ "xyz.openbmc_project.Foo.Bar.Baz.V15"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "pdrType": 9,
+ "entries": [
+ {
+ "entity_path": "/xyz/openbmc_project/foo",
+ "type": 0,
+ "instance": 0,
+ "container": 0,
+ "base_unit": 21,
+ "rate_unit": 3,
+ "effecter_resolution_init": 1,
+ "effecter_data_size": 4,
+ "range_field_format": 4,
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "uint64_t"
+ }
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libpldmresponder/test/pdr_jsons/state_sensor/good/sensor_pdr.json b/libpldmresponder/test/pdr_jsons/state_sensor/good/sensor_pdr.json
new file mode 100644
index 0000000..5e1141a
--- /dev/null
+++ b/libpldmresponder/test/pdr_jsons/state_sensor/good/sensor_pdr.json
@@ -0,0 +1,36 @@
+{
+ "sensorPDRs": [
+ {
+ "pdrType": 4,
+ "entries": [
+ {
+ "type": 5,
+ "instance": 0,
+ "container": 0,
+ "sensors": [
+ {
+ "set": {
+ "id": 1,
+ "size": 1,
+ "states": [
+ 0,
+ 5
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V0",
+ "xyz.openbmc_project.Foo.Bar.V5"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libpldmresponder/test/pdr_jsons/state_sensor/malformed/sensor_pdr.json b/libpldmresponder/test/pdr_jsons/state_sensor/malformed/sensor_pdr.json
new file mode 100644
index 0000000..6d5a941
--- /dev/null
+++ b/libpldmresponder/test/pdr_jsons/state_sensor/malformed/sensor_pdr.json
@@ -0,0 +1,44 @@
+# This JSON is tied with BMC's PDRs. Each entry is used to identify a group of
+# composite sensors.
+{
+ "sensorPDRs": [
+ {
+ # StateSensorPDR
+ # Each sensor in each group of composite sensors has a separate entry and the
+ # supported event states, up to eight.
+ # The "dbus" section contains information about the corresponding D-Bus
+ # property for the sensor and "property_values" are the D-Bus property values
+ # for each corresponding entry in the "states".
+ "pdrType": 4
+ "entries": [
+ {
+ "type": 5,
+ "instance": 0,
+ "container": 0,
+ "sensors": [
+ {
+ "set": {
+ "id": 1,
+ "size": 1,
+ "states": [
+ 0,
+ 5
+ ]
+ },
+ "dbus": {
+ "path": "/foo/bar",
+ "interface": "xyz.openbmc_project.Foo.Bar",
+ "property_name": "propertyName",
+ "property_type": "string",
+ "property_values": [
+ "xyz.openbmc_project.Foo.Bar.V0",
+ "xyz.openbmc_project.Foo.Bar.V5"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file