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/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);
+}