fw-update: Implement inventory manager
1. Discover firmware devices that implement fw update specification
2. Implements request/response for QueryDeviceIdentifiers command
3. Implements request/response for GetFirmwareParameters command
4. Enumerates device identifiers and component information to be used
for fw-update
Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: Ifa035c801a7c62bac9a7e947ed4a43d48f85a4ed
diff --git a/common/types.hpp b/common/types.hpp
index 865f2c4..c6d7734 100644
--- a/common/types.hpp
+++ b/common/types.hpp
@@ -2,14 +2,18 @@
#include <stdint.h>
+#include <bitset>
+#include <map>
#include <set>
#include <string>
+#include <unordered_map>
#include <variant>
#include <vector>
namespace pldm
{
+using eid = uint8_t;
using Request = std::vector<uint8_t>;
using Response = std::vector<uint8_t>;
@@ -27,6 +31,32 @@
} // namespace dbus
+namespace fw_update
+{
+
+// Descriptor definition
+using DescriptorType = uint16_t;
+using DescriptorData = std::vector<uint8_t>;
+using VendorDefinedDescriptorTitle = std::string;
+using VendorDefinedDescriptorData = std::vector<uint8_t>;
+using VendorDefinedDescriptorInfo =
+ std::tuple<VendorDefinedDescriptorTitle, VendorDefinedDescriptorData>;
+using Descriptors =
+ std::map<DescriptorType,
+ std::variant<DescriptorData, VendorDefinedDescriptorInfo>>;
+
+using DescriptorMap = std::unordered_map<eid, Descriptors>;
+
+// Component information
+using CompClassification = uint16_t;
+using CompIdentifier = uint16_t;
+using CompKey = std::pair<CompClassification, CompIdentifier>;
+using CompClassificationIndex = uint8_t;
+using ComponentInfo = std::map<CompKey, CompClassificationIndex>;
+using ComponentInfoMap = std::unordered_map<eid, ComponentInfo>;
+
+} // namespace fw_update
+
namespace pdr
{
diff --git a/fw-update/inventory_manager.cpp b/fw-update/inventory_manager.cpp
new file mode 100644
index 0000000..c0397c2
--- /dev/null
+++ b/fw-update/inventory_manager.cpp
@@ -0,0 +1,245 @@
+#include "inventory_manager.hpp"
+
+#include "libpldm/firmware_update.h"
+
+#include "common/utils.hpp"
+#include "xyz/openbmc_project/Software/Version/server.hpp"
+
+#include <functional>
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+void InventoryManager::discoverFDs(const std::vector<mctp_eid_t>& eids)
+{
+ for (const auto& eid : eids)
+ {
+ auto instanceId = requester.getInstanceId(eid);
+ Request requestMsg(sizeof(pldm_msg_hdr) +
+ PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto rc = encode_query_device_identifiers_req(
+ instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
+ if (rc)
+ {
+ requester.markFree(eid, instanceId);
+ std::cerr << "encode_query_device_identifiers_req failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n";
+ continue;
+ }
+
+ rc = handler.registerRequest(
+ eid, instanceId, PLDM_FWUP, PLDM_QUERY_DEVICE_IDENTIFIERS,
+ std::move(requestMsg),
+ std::move(std::bind_front(&InventoryManager::queryDeviceIdentifiers,
+ this)));
+ if (rc)
+ {
+ std::cerr << "Failed to send QueryDeviceIdentifiers request, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n ";
+ }
+ }
+}
+
+void InventoryManager::queryDeviceIdentifiers(mctp_eid_t eid,
+ const pldm_msg* response,
+ size_t respMsgLen)
+{
+ if (response == nullptr || !respMsgLen)
+ {
+ std::cerr << "No response received for QueryDeviceIdentifiers, EID="
+ << unsigned(eid) << "\n";
+ return;
+ }
+
+ uint8_t completionCode = PLDM_SUCCESS;
+ uint32_t deviceIdentifiersLen = 0;
+ uint8_t descriptorCount = 0;
+ uint8_t* descriptorPtr = nullptr;
+
+ auto rc = decode_query_device_identifiers_resp(
+ response, respMsgLen, &completionCode, &deviceIdentifiersLen,
+ &descriptorCount, &descriptorPtr);
+ if (rc)
+ {
+ std::cerr << "Decoding QueryDeviceIdentifiers response failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n";
+ return;
+ }
+
+ if (completionCode)
+ {
+ std::cerr << "QueryDeviceIdentifiers response failed with error "
+ "completion code, EID="
+ << unsigned(eid) << ", CC=" << unsigned(completionCode)
+ << "\n";
+ return;
+ }
+
+ Descriptors descriptors{};
+ while (descriptorCount-- && (deviceIdentifiersLen > 0))
+ {
+ uint16_t descriptorType = 0;
+ variable_field descriptorData{};
+
+ rc = decode_descriptor_type_length_value(
+ descriptorPtr, deviceIdentifiersLen, &descriptorType,
+ &descriptorData);
+ if (rc)
+ {
+ std::cerr
+ << "Decoding descriptor type, length and value failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n ";
+ return;
+ }
+
+ if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
+ {
+ std::vector<uint8_t> descData(
+ descriptorData.ptr, descriptorData.ptr + descriptorData.length);
+ descriptors.emplace(descriptorType, std::move(descData));
+ }
+ else
+ {
+ uint8_t descriptorTitleStrType = 0;
+ variable_field descriptorTitleStr{};
+ variable_field vendorDefinedDescriptorData{};
+
+ rc = decode_vendor_defined_descriptor_value(
+ descriptorData.ptr, descriptorData.length,
+ &descriptorTitleStrType, &descriptorTitleStr,
+ &vendorDefinedDescriptorData);
+ if (rc)
+ {
+ std::cerr
+ << "Decoding Vendor-defined descriptor value failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n ";
+ return;
+ }
+
+ auto vendorDefinedDescriptorTitleStr =
+ utils::toString(descriptorTitleStr);
+ std::vector<uint8_t> vendorDescData(
+ vendorDefinedDescriptorData.ptr,
+ vendorDefinedDescriptorData.ptr +
+ vendorDefinedDescriptorData.length);
+ descriptors.emplace(descriptorType,
+ std::make_tuple(vendorDefinedDescriptorTitleStr,
+ vendorDescData));
+ }
+ auto nextDescriptorOffset =
+ sizeof(pldm_descriptor_tlv().descriptor_type) +
+ sizeof(pldm_descriptor_tlv().descriptor_length) +
+ descriptorData.length;
+ descriptorPtr += nextDescriptorOffset;
+ deviceIdentifiersLen -= nextDescriptorOffset;
+ }
+
+ descriptorMap.emplace(eid, std::move(descriptors));
+
+ // Send GetFirmwareParameters request
+ sendGetFirmwareParametersRequest(eid);
+}
+
+void InventoryManager::sendGetFirmwareParametersRequest(mctp_eid_t eid)
+{
+ auto instanceId = requester.getInstanceId(eid);
+ Request requestMsg(sizeof(pldm_msg_hdr) +
+ PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto rc = encode_get_firmware_parameters_req(
+ instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
+ if (rc)
+ {
+ requester.markFree(eid, instanceId);
+ std::cerr << "encode_get_firmware_parameters_req failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n";
+ return;
+ }
+
+ rc = handler.registerRequest(
+ eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
+ std::move(requestMsg),
+ std::move(
+ std::bind_front(&InventoryManager::getFirmwareParameters, this)));
+ if (rc)
+ {
+ std::cerr << "Failed to send GetFirmwareParameters request, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n ";
+ }
+}
+
+void InventoryManager::getFirmwareParameters(mctp_eid_t eid,
+ const pldm_msg* response,
+ size_t respMsgLen)
+{
+ if (response == nullptr || !respMsgLen)
+ {
+ std::cerr << "No response received for GetFirmwareParameters, EID="
+ << unsigned(eid) << "\n";
+ descriptorMap.erase(eid);
+ return;
+ }
+
+ pldm_get_firmware_parameters_resp fwParams{};
+ variable_field activeCompImageSetVerStr{};
+ variable_field pendingCompImageSetVerStr{};
+ variable_field compParamTable{};
+
+ auto rc = decode_get_firmware_parameters_resp(
+ response, respMsgLen, &fwParams, &activeCompImageSetVerStr,
+ &pendingCompImageSetVerStr, &compParamTable);
+ if (rc)
+ {
+ std::cerr << "Decoding GetFirmwareParameters response failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n";
+ return;
+ }
+
+ if (fwParams.completion_code)
+ {
+ std::cerr << "GetFirmwareParameters response failed with error "
+ "completion code, EID="
+ << unsigned(eid)
+ << ", CC=" << unsigned(fwParams.completion_code) << "\n";
+ return;
+ }
+
+ auto compParamPtr = compParamTable.ptr;
+ auto compParamTableLen = compParamTable.length;
+ pldm_component_parameter_entry compEntry{};
+ variable_field activeCompVerStr{};
+ variable_field pendingCompVerStr{};
+
+ ComponentInfo componentInfo{};
+ while (fwParams.comp_count-- && (compParamTableLen > 0))
+ {
+ auto rc = decode_get_firmware_parameters_resp_comp_entry(
+ compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
+ &pendingCompVerStr);
+ if (rc)
+ {
+ std::cerr << "Decoding component parameter table entry failed, EID="
+ << unsigned(eid) << ", RC=" << rc << "\n";
+ return;
+ }
+
+ auto compClassification = compEntry.comp_classification;
+ auto compIdentifier = compEntry.comp_identifier;
+ componentInfo.emplace(
+ std::make_pair(compClassification, compIdentifier),
+ compEntry.comp_classification_index);
+ compParamPtr += sizeof(pldm_component_parameter_entry) +
+ activeCompVerStr.length + pendingCompVerStr.length;
+ compParamTableLen -= sizeof(pldm_component_parameter_entry) +
+ activeCompVerStr.length + pendingCompVerStr.length;
+ }
+ componentInfoMap.emplace(eid, std::move(componentInfo));
+}
+
+} // namespace fw_update
+
+} // namespace pldm
\ No newline at end of file
diff --git a/fw-update/inventory_manager.hpp b/fw-update/inventory_manager.hpp
new file mode 100644
index 0000000..a14d58c
--- /dev/null
+++ b/fw-update/inventory_manager.hpp
@@ -0,0 +1,108 @@
+#pragma once
+
+#include "libpldm/requester/pldm.h"
+
+#include "common/types.hpp"
+#include "pldmd/dbus_impl_requester.hpp"
+#include "requester/handler.hpp"
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+/** @class InventoryManager
+ *
+ * InventoryManager class manages the software inventory of firmware devices
+ * managed by the BMC. It discovers the firmware identifiers and the component
+ * details of the FD. Firmware identifiers, component details and update
+ * capabilities of FD are populated by the InventoryManager and is used for the
+ * firmware update of the FDs.
+ */
+class InventoryManager
+{
+ public:
+ InventoryManager() = delete;
+ InventoryManager(const InventoryManager&) = delete;
+ InventoryManager(InventoryManager&&) = delete;
+ InventoryManager& operator=(const InventoryManager&) = delete;
+ InventoryManager& operator=(InventoryManager&&) = delete;
+ ~InventoryManager() = default;
+
+ /** @brief Constructor
+ *
+ * @param[in] handler - PLDM request handler
+ * @param[in] requester - Managing instance ID for PLDM requests
+ * @param[out] descriptorMap - Populate the firmware identifers for the
+ * FDs managed by the BMC.
+ * @param[out] componentInfoMap - Populate the component info for the FDs
+ * managed by the BMC.
+ */
+ explicit InventoryManager(
+ pldm::requester::Handler<pldm::requester::Request>& handler,
+ pldm::dbus_api::Requester& requester, DescriptorMap& descriptorMap,
+ ComponentInfoMap& componentInfoMap) :
+ handler(handler),
+ requester(requester), descriptorMap(descriptorMap),
+ componentInfoMap(componentInfoMap)
+ {}
+
+ /** @brief Discover the firmware identifiers and component details of FDs
+ *
+ * Inventory commands QueryDeviceIdentifiers and GetFirmwareParmeters
+ * commands are sent to every FD and the response is used to populate
+ * the firmware identifiers and component details of the FDs.
+ *
+ * @param[in] eids - MCTP endpoint ID of the FDs
+ */
+ void discoverFDs(const std::vector<mctp_eid_t>& eids);
+
+ /** @brief Handler for QueryDeviceIdentifiers command response
+ *
+ * The response of the QueryDeviceIdentifiers is processed and firmware
+ * identifiers of the FD is updated. GetFirmwareParameters command request
+ * is sent to the FD.
+ *
+ * @param[in] eid - Remote MCTP endpoint
+ * @param[in] response - PLDM response message
+ * @param[in] respMsgLen - Response message length
+ */
+ void queryDeviceIdentifiers(mctp_eid_t eid, const pldm_msg* response,
+ size_t respMsgLen);
+
+ /** @brief Handler for GetFirmwareParameters command response
+ *
+ * Handling the response of GetFirmwareParameters command and create
+ * software version D-Bus objects.
+ *
+ * @param[in] eid - Remote MCTP endpoint
+ * @param[in] response - PLDM response message
+ * @param[in] respMsgLen - Response message length
+ */
+ void getFirmwareParameters(mctp_eid_t eid, const pldm_msg* response,
+ size_t respMsgLen);
+
+ private:
+ /** @brief Send GetFirmwareParameters command request
+ *
+ * @param[in] eid - Remote MCTP endpoint
+ */
+ void sendGetFirmwareParametersRequest(mctp_eid_t eid);
+
+ /** @brief PLDM request handler */
+ pldm::requester::Handler<pldm::requester::Request>& handler;
+
+ /** @brief D-Bus API for managing instance ID*/
+ pldm::dbus_api::Requester& requester;
+
+ /** @brief Device identifiers of the managed FDs */
+ DescriptorMap& descriptorMap;
+
+ /** @brief Component information needed for the update of the managed FDs */
+ ComponentInfoMap& componentInfoMap;
+};
+
+} // namespace fw_update
+
+} // namespace pldm
diff --git a/fw-update/test/inventory_manager_test.cpp b/fw-update/test/inventory_manager_test.cpp
new file mode 100644
index 0000000..5b14aac
--- /dev/null
+++ b/fw-update/test/inventory_manager_test.cpp
@@ -0,0 +1,188 @@
+#include "libpldm/firmware_update.h"
+
+#include "common/utils.hpp"
+#include "fw-update/inventory_manager.hpp"
+#include "requester/test/mock_request.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace pldm;
+using namespace std::chrono;
+using namespace pldm::fw_update;
+
+class InventoryManagerTest : public testing::Test
+{
+ protected:
+ InventoryManagerTest() :
+ event(sdeventplus::Event::get_default()),
+ dbusImplRequester(pldm::utils::DBusHandler::getBus(),
+ "/xyz/openbmc_project/pldm"),
+ reqHandler(fd, event, dbusImplRequester, false, seconds(1), 2,
+ milliseconds(100)),
+ inventoryManager(reqHandler, dbusImplRequester, outDescriptorMap,
+ outComponentInfoMap)
+ {}
+
+ int fd = -1;
+ sdeventplus::Event event;
+ pldm::dbus_api::Requester dbusImplRequester;
+ requester::Handler<requester::Request> reqHandler;
+ InventoryManager inventoryManager;
+ DescriptorMap outDescriptorMap{};
+ ComponentInfoMap outComponentInfoMap{};
+};
+
+TEST_F(InventoryManagerTest, handleQueryDeviceIdentifiersResponse)
+{
+ constexpr size_t respPayloadLength1 = 49;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength1>
+ queryDeviceIdentifiersResp1{
+ 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00,
+ 0x04, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x02, 0x00, 0x10, 0x00, 0x12,
+ 0x44, 0xd2, 0x64, 0x8d, 0x7d, 0x47, 0x18, 0xa0, 0x30, 0xfc, 0x8a,
+ 0x56, 0x58, 0x7d, 0x5b, 0xFF, 0xFF, 0x0B, 0x00, 0x01, 0x07, 0x4f,
+ 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43, 0x01, 0x02};
+ auto responseMsg1 =
+ reinterpret_cast<const pldm_msg*>(queryDeviceIdentifiersResp1.data());
+ inventoryManager.queryDeviceIdentifiers(1, responseMsg1,
+ respPayloadLength1);
+
+ DescriptorMap descriptorMap1{
+ {0x01,
+ {{PLDM_FWUP_IANA_ENTERPRISE_ID,
+ std::vector<uint8_t>{0x0a, 0x0b, 0x0c, 0xd}},
+ {PLDM_FWUP_UUID,
+ std::vector<uint8_t>{0x12, 0x44, 0xd2, 0x64, 0x8d, 0x7d, 0x47, 0x18,
+ 0xa0, 0x30, 0xfc, 0x8a, 0x56, 0x58, 0x7d,
+ 0x5b}},
+ {PLDM_FWUP_VENDOR_DEFINED,
+ std::make_tuple("OpenBMC", std::vector<uint8_t>{0x01, 0x02})}}}};
+
+ EXPECT_EQ(outDescriptorMap.size(), descriptorMap1.size());
+ EXPECT_EQ(outDescriptorMap, descriptorMap1);
+
+ constexpr size_t respPayloadLength2 = 26;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength2>
+ queryDeviceIdentifiersResp2{
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x00, 0x10, 0x00, 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49,
+ 0x43, 0x98, 0x00, 0xA0, 0x2F, 0x59, 0x9A, 0xCA, 0x02};
+ auto responseMsg2 =
+ reinterpret_cast<const pldm_msg*>(queryDeviceIdentifiersResp2.data());
+ inventoryManager.queryDeviceIdentifiers(2, responseMsg2,
+ respPayloadLength2);
+ DescriptorMap descriptorMap2{
+ {0x01,
+ {{PLDM_FWUP_IANA_ENTERPRISE_ID,
+ std::vector<uint8_t>{0x0a, 0x0b, 0x0c, 0xd}},
+ {PLDM_FWUP_UUID,
+ std::vector<uint8_t>{0x12, 0x44, 0xd2, 0x64, 0x8d, 0x7d, 0x47, 0x18,
+ 0xa0, 0x30, 0xfc, 0x8a, 0x56, 0x58, 0x7d,
+ 0x5b}},
+ {PLDM_FWUP_VENDOR_DEFINED,
+ std::make_tuple("OpenBMC", std::vector<uint8_t>{0x01, 0x02})}}},
+ {0x02,
+ {{PLDM_FWUP_UUID,
+ std::vector<uint8_t>{0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
+ 0x98, 0x00, 0xA0, 0x2F, 0x59, 0x9A, 0xCA,
+ 0x02}}}}};
+ EXPECT_EQ(outDescriptorMap.size(), descriptorMap2.size());
+ EXPECT_EQ(outDescriptorMap, descriptorMap2);
+}
+
+TEST_F(InventoryManagerTest, handleQueryDeviceIdentifiersResponseErrorCC)
+{
+ constexpr size_t respPayloadLength = 1;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength>
+ queryDeviceIdentifiersResp{0x00, 0x00, 0x00, 0x01};
+ auto responseMsg =
+ reinterpret_cast<const pldm_msg*>(queryDeviceIdentifiersResp.data());
+ inventoryManager.queryDeviceIdentifiers(1, responseMsg, respPayloadLength);
+ EXPECT_EQ(outDescriptorMap.size(), 0);
+}
+
+TEST_F(InventoryManagerTest, getFirmwareParametersResponse)
+{
+ // constexpr uint16_t compCount = 2;
+ // constexpr std::string_view activeCompImageSetVersion{"DeviceVer1.0"};
+ // constexpr std::string_view activeCompVersion1{"Comp1v2.0"};
+ // constexpr std::string_view activeCompVersion2{"Comp2v3.0"};
+ constexpr uint16_t compClassification1 = 10;
+ constexpr uint16_t compIdentifier1 = 300;
+ constexpr uint8_t compClassificationIndex1 = 20;
+ constexpr uint16_t compClassification2 = 16;
+ constexpr uint16_t compIdentifier2 = 301;
+ constexpr uint8_t compClassificationIndex2 = 30;
+
+ constexpr size_t respPayloadLength1 = 119;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength1>
+ getFirmwareParametersResp1{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
+ 0x0c, 0x00, 0x00, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65,
+ 0x72, 0x31, 0x2e, 0x30, 0x0a, 0x00, 0x2c, 0x01, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
+ 0x6f, 0x6d, 0x70, 0x31, 0x76, 0x32, 0x2e, 0x30, 0x10, 0x00, 0x2d,
+ 0x01, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6d, 0x70, 0x32, 0x76, 0x33, 0x2e,
+ 0x30};
+ auto responseMsg1 =
+ reinterpret_cast<const pldm_msg*>(getFirmwareParametersResp1.data());
+ inventoryManager.getFirmwareParameters(1, responseMsg1, respPayloadLength1);
+
+ ComponentInfoMap componentInfoMap1{
+ {1,
+ {{std::make_pair(compClassification1, compIdentifier1),
+ compClassificationIndex1},
+ {std::make_pair(compClassification2, compIdentifier2),
+ compClassificationIndex2}}}};
+ EXPECT_EQ(outComponentInfoMap.size(), componentInfoMap1.size());
+ EXPECT_EQ(outComponentInfoMap, componentInfoMap1);
+
+ // constexpr uint16_t compCount = 1;
+ // constexpr std::string_view activeCompImageSetVersion{"DeviceVer2.0"};
+ // constexpr std::string_view activeCompVersion1{"Comp3v4.0"};
+ constexpr uint16_t compClassification3 = 2;
+ constexpr uint16_t compIdentifier3 = 302;
+ constexpr uint8_t compClassificationIndex3 = 40;
+
+ constexpr size_t respPayloadLength2 = 119;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength2>
+ getFirmwareParametersResp2{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x0c, 0x00, 0x00, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65,
+ 0x72, 0x32, 0x2e, 0x30, 0x02, 0x00, 0x2e, 0x01, 0x28, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
+ 0x6f, 0x6d, 0x70, 0x33, 0x76, 0x34, 0x2e, 0x30};
+ auto responseMsg2 =
+ reinterpret_cast<const pldm_msg*>(getFirmwareParametersResp2.data());
+ inventoryManager.getFirmwareParameters(2, responseMsg2, respPayloadLength2);
+
+ ComponentInfoMap componentInfoMap2{
+ {1,
+ {{std::make_pair(compClassification1, compIdentifier1),
+ compClassificationIndex1},
+ {std::make_pair(compClassification2, compIdentifier2),
+ compClassificationIndex2}}},
+ {2,
+ {{std::make_pair(compClassification3, compIdentifier3),
+ compClassificationIndex3}}}};
+ EXPECT_EQ(outComponentInfoMap.size(), componentInfoMap2.size());
+ EXPECT_EQ(outComponentInfoMap, componentInfoMap2);
+}
+
+TEST_F(InventoryManagerTest, getFirmwareParametersResponseErrorCC)
+{
+ constexpr size_t respPayloadLength = 1;
+ constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) + respPayloadLength>
+ getFirmwareParametersResp{0x00, 0x00, 0x00, 0x01};
+ auto responseMsg =
+ reinterpret_cast<const pldm_msg*>(getFirmwareParametersResp.data());
+ inventoryManager.getFirmwareParameters(1, responseMsg, respPayloadLength);
+ EXPECT_EQ(outComponentInfoMap.size(), 0);
+}
diff --git a/fw-update/test/meson.build b/fw-update/test/meson.build
new file mode 100644
index 0000000..e88466d
--- /dev/null
+++ b/fw-update/test/meson.build
@@ -0,0 +1,26 @@
+fw_update_test_src = declare_dependency(
+ sources: [
+ '../inventory_manager.cpp',
+ '../../common/utils.cpp',
+ '../../pldmd/dbus_impl_requester.cpp',
+ '../../pldmd/instance_id.cpp'])
+
+tests = [
+ 'inventory_manager_test',
+]
+
+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: [
+ fw_update_test_src,
+ gtest,
+ libpldm_dep,
+ nlohmann_json,
+ phosphor_dbus_interfaces,
+ sdbusplus,
+ sdeventplus]),
+ workdir: meson.current_source_dir())
+endforeach
diff --git a/meson.build b/meson.build
index 4757fe6..f63d950 100644
--- a/meson.build
+++ b/meson.build
@@ -194,6 +194,7 @@
'pldmd/dbus_impl_requester.cpp',
'pldmd/instance_id.cpp',
'pldmd/dbus_impl_pdr.cpp',
+ 'fw-update/inventory_manager.cpp',
implicit_include_directories: false,
dependencies: deps,
install: true,
@@ -237,6 +238,7 @@
if get_option('tests').enabled()
subdir('common/test')
+ subdir('fw-update/test')
subdir('host-bmc/test')
subdir('requester/test')
subdir('test')