Implement PDR.FindStateSensorPDR DBus API

This commit implements a DBus API defined at
https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-dbus-interfaces/+/32905
to find the stateSensorPDR based on the entity ID
and stateSetID

Tested: Tested ok in fp5280g2 system
busctl call xyz.openbmc_project.PLDM /xyz/openbmc_project/pldm xyz.openbmc_project.PLDM.PDR FindStateSensorPDR yqq 1 5 1
aay 1 27 4 0 0 0 1 4 0 0 17 0 0 0 1 0 5 0 0 0 0 0 0 0 1 1 0 1 33

Signed-off-by: Chicago Duan <duanzhijia01@inspur.com>
Change-Id: I2b4ea63df4890933d1c70ac48a6829e7c1204f69
diff --git a/dbus_impl_pdr.cpp b/dbus_impl_pdr.cpp
index c35e422..fb939e0 100644
--- a/dbus_impl_pdr.cpp
+++ b/dbus_impl_pdr.cpp
@@ -29,5 +29,17 @@
 
     return pdrs;
 }
+
+std::vector<std::vector<uint8_t>>
+    Pdr::findStateSensorPDR(uint8_t tid, uint16_t entityID, uint16_t stateSetId)
+{
+    auto pdrs =
+        pldm::utils::findStateSensorPDR(tid, entityID, stateSetId, pdrRepo);
+    if (pdrs.empty())
+    {
+        throw ResourceNotFound();
+    }
+    return pdrs;
+}
 } // namespace dbus_api
 } // namespace pldm
diff --git a/dbus_impl_pdr.hpp b/dbus_impl_pdr.hpp
index 16f5564..5016bb3 100644
--- a/dbus_impl_pdr.hpp
+++ b/dbus_impl_pdr.hpp
@@ -57,11 +57,8 @@
      *  @param[in] stateSetId - value that identifies PLDM State set.
      */
     std::vector<std::vector<uint8_t>>
-        findStateSensorPDR(uint8_t /*tid*/, uint16_t /*entityID*/,
-                           uint16_t /*stateSetId*/) override
-    {
-        return {};
-    }
+        findStateSensorPDR(uint8_t tid, uint16_t entityID,
+                           uint16_t stateSetId) override;
 
   private:
     /** @brief pointer to BMC's primary PDR repo */
diff --git a/test/pldm_utils_test.cpp b/test/pldm_utils_test.cpp
index 4af91d1..4684f9a 100644
--- a/test/pldm_utils_test.cpp
+++ b/test/pldm_utils_test.cpp
@@ -480,3 +480,403 @@
 
     pldm_pdr_destroy(repo);
 }
+
+TEST(FindStateSensorPDR, testOneMatch)
+{
+
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 5;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 1;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(pdr, record[0]);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testNoMatch)
+{
+
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 55;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 1;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(record.empty(), true);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testEmptyRepo)
+{
+
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(record.empty(), true);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testMoreMatch)
+{
+
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 5;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 1;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    std::vector<uint8_t> pdr_second(
+        sizeof(struct pldm_state_sensor_pdr) - sizeof(uint8_t) +
+        sizeof(struct state_sensor_possible_states));
+
+    auto rec_second =
+        reinterpret_cast<pldm_state_sensor_pdr*>(pdr_second.data());
+
+    auto state_second = reinterpret_cast<state_sensor_possible_states*>(
+        rec_second->possible_states);
+
+    rec_second->hdr.type = 4;
+    rec_second->hdr.record_handle = 2;
+    rec_second->entity_type = 5;
+    rec_second->container_id = 0;
+    rec_second->composite_sensor_count = 1;
+    state_second->state_set_id = 1;
+    state_second->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr_second.data(), pdr_second.size(), 0, false);
+
+    uint16_t entityID_ = 5;
+    uint16_t stateSetId_ = 1;
+
+    auto record = findStateSensorPDR(tid, entityID_, stateSetId_, repo);
+
+    EXPECT_EQ(pdr, record[0]);
+    EXPECT_EQ(pdr_second, record[1]);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testManyNoMatch)
+{
+
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 56;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 2;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    std::vector<uint8_t> pdr_second(
+        sizeof(struct pldm_state_sensor_pdr) - sizeof(uint8_t) +
+        sizeof(struct state_sensor_possible_states));
+
+    auto rec_second =
+        reinterpret_cast<pldm_state_sensor_pdr*>(pdr_second.data());
+
+    auto state_second = reinterpret_cast<state_sensor_possible_states*>(
+        rec_second->possible_states);
+
+    rec_second->hdr.type = 4;
+    rec_second->hdr.record_handle = 2;
+    rec_second->entity_type = 66;
+    rec_second->container_id = 0;
+    rec_second->composite_sensor_count = 1;
+    state_second->state_set_id = 3;
+    state_second->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr_second.data(), pdr_second.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(record.empty(), true);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testOneMatchOneNoMatch)
+{
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 10;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 20;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    std::vector<uint8_t> pdr_second(
+        sizeof(struct pldm_state_sensor_pdr) - sizeof(uint8_t) +
+        sizeof(struct state_sensor_possible_states));
+
+    auto rec_second =
+        reinterpret_cast<pldm_state_sensor_pdr*>(pdr_second.data());
+
+    auto state_second = reinterpret_cast<state_sensor_possible_states*>(
+        rec_second->possible_states);
+
+    rec_second->hdr.type = 4;
+    rec_second->hdr.record_handle = 2;
+    rec_second->entity_type = 5;
+    rec_second->container_id = 0;
+    rec_second->composite_sensor_count = 1;
+    state_second->state_set_id = 1;
+    state_second->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr_second.data(), pdr_second.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(pdr_second, record[0]);
+    EXPECT_EQ(record.size(), 1);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testOneMatchManyNoMatch)
+{
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 6;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 1;
+    state->state_set_id = 9;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    std::vector<uint8_t> pdr_second(
+        sizeof(struct pldm_state_sensor_pdr) - sizeof(uint8_t) +
+        sizeof(struct state_sensor_possible_states));
+
+    auto rec_second =
+        reinterpret_cast<pldm_state_sensor_pdr*>(pdr_second.data());
+
+    auto state_second = reinterpret_cast<state_sensor_possible_states*>(
+        rec_second->possible_states);
+
+    rec_second->hdr.type = 4;
+    rec_second->hdr.record_handle = 2;
+    rec_second->entity_type = 5;
+    rec_second->container_id = 0;
+    rec_second->composite_sensor_count = 1;
+    state_second->state_set_id = 1;
+    state_second->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr_second.data(), pdr_second.size(), 0, false);
+
+    std::vector<uint8_t> pdr_third(sizeof(struct pldm_state_sensor_pdr) -
+                                   sizeof(uint8_t) +
+                                   sizeof(struct state_sensor_possible_states));
+
+    auto rec_third = reinterpret_cast<pldm_state_sensor_pdr*>(pdr_third.data());
+
+    auto state_third = reinterpret_cast<state_sensor_possible_states*>(
+        rec_third->possible_states);
+
+    rec_third->hdr.type = 4;
+    rec_third->hdr.record_handle = 3;
+    rec_third->entity_type = 7;
+    rec_third->container_id = 0;
+    rec_third->composite_sensor_count = 1;
+    state_third->state_set_id = 12;
+    state_third->possible_states_size = 1;
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(pdr_second, record[0]);
+    EXPECT_EQ(record.size(), 1);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testCompositeSensor)
+{
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 5;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 3;
+    state->state_set_id = 2;
+    state->possible_states_size = 1;
+
+    state->state_set_id = 7;
+    state->possible_states_size = 1;
+
+    state->state_set_id = 1;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(pdr, record[0]);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(FindStateSensorPDR, testNoMatchCompositeSensor)
+{
+    auto repo = pldm_pdr_init();
+    uint8_t tid = 1;
+    uint16_t entityID = 5;
+    uint16_t stateSetId = 1;
+
+    std::vector<uint8_t> pdr(sizeof(struct pldm_state_sensor_pdr) -
+                             sizeof(uint8_t) +
+                             sizeof(struct state_sensor_possible_states));
+
+    auto rec = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
+
+    auto state =
+        reinterpret_cast<state_sensor_possible_states*>(rec->possible_states);
+
+    rec->hdr.type = 4;
+    rec->hdr.record_handle = 1;
+    rec->entity_type = 21;
+    rec->container_id = 0;
+    rec->composite_sensor_count = 3;
+    state->state_set_id = 15;
+    state->possible_states_size = 1;
+
+    state->state_set_id = 19;
+    state->possible_states_size = 1;
+
+    state->state_set_id = 39;
+    state->possible_states_size = 1;
+
+    pldm_pdr_add(repo, pdr.data(), pdr.size(), 0, false);
+
+    auto record = findStateSensorPDR(tid, entityID, stateSetId, repo);
+
+    EXPECT_EQ(record.empty(), true);
+
+    pldm_pdr_destroy(repo);
+}
\ No newline at end of file
diff --git a/utils.cpp b/utils.cpp
index 27fda03..7402df5 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -76,6 +76,59 @@
     return pdrs;
 }
 
+std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t /*tid*/,
+                                                     uint16_t entityID,
+                                                     uint16_t stateSetId,
+                                                     const pldm_pdr* repo)
+{
+    uint8_t* outData = nullptr;
+    uint32_t size{};
+    const pldm_pdr_record* record{};
+    std::vector<std::vector<uint8_t>> pdrs;
+    try
+    {
+        do
+        {
+            record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_SENSOR_PDR,
+                                                  record, &outData, &size);
+            if (record)
+            {
+                auto pdr = reinterpret_cast<pldm_state_sensor_pdr*>(outData);
+                auto compositeSensorCount = pdr->composite_sensor_count;
+
+                for (auto sensors = 0x00; sensors < compositeSensorCount;
+                     sensors++)
+                {
+                    auto possibleStates =
+                        reinterpret_cast<state_sensor_possible_states*>(
+                            pdr->possible_states);
+                    auto setId = possibleStates->state_set_id;
+                    auto possibleStateSize =
+                        possibleStates->possible_states_size;
+
+                    if (pdr->entity_type == entityID && setId == stateSetId)
+                    {
+                        std::vector<uint8_t> sensor_pdr(&outData[0],
+                                                        &outData[size]);
+                        pdrs.emplace_back(std::move(sensor_pdr));
+                        break;
+                    }
+                    possibleStates += possibleStateSize + sizeof(setId) +
+                                      sizeof(possibleStateSize);
+                }
+            }
+
+        } while (record);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << " Failed to obtain a record. ERROR =" << e.what()
+                  << std::endl;
+    }
+
+    return pdrs;
+}
+
 uint8_t readHostEID()
 {
     uint8_t eid{};
diff --git a/utils.hpp b/utils.hpp
index 0814de2..715d509 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -270,6 +270,17 @@
                                                        uint16_t entityID,
                                                        uint16_t stateSetId,
                                                        const pldm_pdr* repo);
+/** @brief Find State Sensor PDR
+ *  @param[in] tid - PLDM terminus ID.
+ *  @param[in] entityID - entity that can be associated with PLDM State set.
+ *  @param[in] stateSetId - value that identifies PLDM State set.
+ *  @param[in] repo - pointer to BMC's primary PDR repo.
+ *  @return array[array[uint8_t]] - StateSensorPDRs
+ */
+std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid,
+                                                     uint16_t entityID,
+                                                     uint16_t stateSetId,
+                                                     const pldm_pdr* repo);
 
 } // namespace utils
 } // namespace pldm