libpldm: add APIs for PDR operations

Add APIs for PDR operations such as:
- Creating/destroying a PDR repository
- Adding record to a PDR repository
- Finding records in a PDR repository

Tested with unit tests.

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: Ied6ae1755a1a249b563bf0fa953586789810b3dc
diff --git a/libpldm/meson.build b/libpldm/meson.build
index 63bd8ad..9d24b2c 100644
--- a/libpldm/meson.build
+++ b/libpldm/meson.build
@@ -15,7 +15,8 @@
   'bios.c',
   'bios_table.c',
   'fru.c',
-  'utils.c'
+  'utils.c',
+  'pdr.c'
 ]
 
 libpldm_headers = ['.', '..']
diff --git a/libpldm/pdr.c b/libpldm/pdr.c
new file mode 100644
index 0000000..692a035
--- /dev/null
+++ b/libpldm/pdr.c
@@ -0,0 +1,238 @@
+#include "pdr.h"
+#include "platform.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct pldm_pdr_record {
+	uint32_t record_handle;
+	uint32_t size;
+	uint8_t *data;
+	struct pldm_pdr_record *next;
+} pldm_pdr_record;
+
+typedef struct pldm_pdr {
+	uint32_t record_count;
+	uint32_t size;
+	uint32_t last_used_record_handle;
+	pldm_pdr_record *first;
+	pldm_pdr_record *last;
+} pldm_pdr;
+
+static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
+					      const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	if (record == repo->last) {
+		return 0;
+	}
+	return record->next->record_handle;
+}
+
+static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	if (repo->first == NULL) {
+		assert(repo->last == NULL);
+		repo->first = record;
+		repo->last = record;
+	} else {
+		repo->last->next = record;
+		repo->last = record;
+	}
+	repo->size += record->size;
+	repo->last_used_record_handle = record->record_handle;
+	++repo->record_count;
+}
+
+static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+	assert(repo->last_used_record_handle != UINT32_MAX);
+
+	return repo->last_used_record_handle + 1;
+}
+
+static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
+					const uint8_t *data, uint32_t size,
+					uint32_t record_handle)
+{
+	assert(repo != NULL);
+	assert(size != 0);
+
+	pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
+	assert(record != NULL);
+	record->record_handle =
+	    record_handle == 0 ? get_new_record_handle(repo) : record_handle;
+	record->size = size;
+	if (data != NULL) {
+		record->data = malloc(size);
+		assert(record->data != NULL);
+		memcpy(record->data, data, size);
+		/* If record handle is 0, that is an indication for this API to
+		 * compute a new handle. For that reason, the computed handle
+		 * needs to be populated in the PDR header. For a case where the
+		 * caller supplied the record handle, it would exist in the
+		 * header already.
+		 */
+		if (!record_handle) {
+			struct pldm_pdr_hdr *hdr =
+			    (struct pldm_pdr_hdr *)(record->data);
+			hdr->record_handle = record->record_handle;
+		}
+	}
+	record->next = NULL;
+
+	return record;
+}
+
+uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+		      uint32_t record_handle)
+{
+	assert(size != 0);
+	assert(data != NULL);
+
+	pldm_pdr_record *record =
+	    make_new_record(repo, data, size, record_handle);
+	add_record(repo, record);
+
+	return record->record_handle;
+}
+
+pldm_pdr *pldm_pdr_init()
+{
+	pldm_pdr *repo = malloc(sizeof(pldm_pdr));
+	assert(repo != NULL);
+	repo->record_count = 0;
+	repo->size = 0;
+	repo->last_used_record_handle = 0;
+	repo->first = NULL;
+	repo->last = NULL;
+
+	return repo;
+}
+
+void pldm_pdr_destroy(pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->data) {
+			free(record->data);
+			record->data = NULL;
+		}
+		free(record);
+		record = next;
+	}
+	free(repo);
+}
+
+const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
+					    uint32_t record_handle,
+					    uint8_t **data, uint32_t *size,
+					    uint32_t *next_record_handle)
+{
+	assert(repo != NULL);
+	assert(data != NULL);
+	assert(size != NULL);
+	assert(next_record_handle != NULL);
+
+	if (!record_handle && (repo->first != NULL)) {
+		record_handle = repo->first->record_handle;
+	}
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		if (record->record_handle == record_handle) {
+			*size = record->size;
+			*data = record->data;
+			*next_record_handle =
+			    get_next_record_handle(repo, record);
+			return record;
+		}
+		record = record->next;
+	}
+
+	*size = 0;
+	*next_record_handle = 0;
+	return NULL;
+}
+
+const pldm_pdr_record *
+pldm_pdr_get_next_record(const pldm_pdr *repo,
+			 const pldm_pdr_record *curr_record, uint8_t **data,
+			 uint32_t *size, uint32_t *next_record_handle)
+{
+	assert(repo != NULL);
+	assert(curr_record != NULL);
+	assert(data != NULL);
+	assert(size != NULL);
+	assert(next_record_handle != NULL);
+
+	if (curr_record == repo->last) {
+		*data = NULL;
+		*size = 0;
+		*next_record_handle = get_next_record_handle(repo, curr_record);
+		return NULL;
+	}
+
+	*next_record_handle = get_next_record_handle(repo, curr_record->next);
+	*data = curr_record->next->data;
+	*size = curr_record->next->size;
+	return curr_record->next;
+}
+
+const pldm_pdr_record *
+pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
+			     const pldm_pdr_record *curr_record, uint8_t **data,
+			     uint32_t *size)
+{
+	assert(repo != NULL);
+	assert(data != NULL);
+	assert(size != NULL);
+
+	pldm_pdr_record *record = repo->first;
+	if (curr_record != NULL) {
+		record = curr_record->next;
+	}
+	while (record != NULL) {
+		struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
+		if (hdr->type == pdr_type) {
+			*size = record->size;
+			*data = record->data;
+			return record;
+		}
+		record = record->next;
+	}
+
+	*size = 0;
+	return NULL;
+}
+
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->record_count;
+}
+
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->size;
+}
+
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
+				    const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	return record->record_handle;
+}
diff --git a/libpldm/pdr.h b/libpldm/pdr.h
new file mode 100644
index 0000000..eb4a3bb
--- /dev/null
+++ b/libpldm/pdr.h
@@ -0,0 +1,140 @@
+#ifndef PDR_H
+#define PDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/** @struct pldm_pdr
+ *  opaque structure that acts as a handle to a PDR repository
+ */
+typedef struct pldm_pdr pldm_pdr;
+
+/** @struct pldm_pdr_record
+ *  opaque structure that acts as a handle to a PDR record
+ */
+typedef struct pldm_pdr_record pldm_pdr_record;
+
+/* ====================== */
+/* Common PDR access APIs */
+/* ====================== */
+
+/** @brief Make a new PDR repository
+ *
+ *  @return opaque pointer that acts as a handle to the repository; NULL if no
+ *  repository could be created
+ *
+ *  @note  Caller may make multiple repositories (for its own PDRs, as well as
+ *  for PDRs received by other entities) and can associate the returned handle
+ *  to a PLDM terminus id.
+ */
+pldm_pdr *pldm_pdr_init();
+
+/** @brief Destroy a PDR repository (and free up associated resources)
+ *
+ *  @param[in/out] repo - pointer to opaque pointer acting as a PDR repo handle
+ */
+void pldm_pdr_destroy(pldm_pdr *repo);
+
+/** @brief Get number of records in a PDR repository
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *
+ *  @return uint32_t - number of records
+ */
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo);
+
+/** @brief Get size of a PDR repository, in bytes
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *
+ *  @return uint32_t - size in bytes
+ */
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo);
+
+/** @brief Add a PDR record to a PDR repository
+ *
+ *  @param[in/out] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] data - pointer to a PDR record, pointing to a PDR definition as
+ *  per DSP0248. This data is memcpy'd.
+ *  @param[in] size - size of input PDR record in bytes
+ *  @param[in] record_handle - record handle of input PDR record; if this is set
+ *  to 0, then a record handle is computed and assigned to this PDR record
+ *
+ *  @return uint32_t - record handle assigned to PDR record
+ */
+uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+		      uint32_t record_handle);
+
+/** @brief Get record handle of a PDR record
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] record - opaque pointer acting as a PDR record handle
+ *
+ *  @return uint32_t - record handle assigned to PDR record; 0 if record is not
+ *  found
+ */
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
+				    const pldm_pdr_record *record);
+
+/** @brief Find PDR record by record handle
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] record_handle - input record handle
+ *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ *                        return
+ *  @param[out] size - *size will be size of PDR record
+ *  @param[out] next_record_handle - *next_record_handle will be the record
+ *  handle of record next to the returned PDR record
+ *
+ *  @return opaque pointer acting as PDR record handle, will be NULL if record
+ *  was not found
+ */
+const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
+					    uint32_t record_handle,
+					    uint8_t **data, uint32_t *size,
+					    uint32_t *next_record_handle);
+
+/** @brief Get PDR record next to input PDR record
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] curr_record - opaque pointer acting as a PDR record handle
+ *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ *                        return
+ *  @param[out] size - *size will be size of PDR record
+ *  @param[out] next_record_handle - *next_record_handle will be the record
+ *  handle of record nect to the returned PDR record
+ *
+ *  @return opaque pointer acting as PDR record handle, will be NULL if record
+ *  was not found
+ */
+const pldm_pdr_record *
+pldm_pdr_get_next_record(const pldm_pdr *repo,
+			 const pldm_pdr_record *curr_record, uint8_t **data,
+			 uint32_t *size, uint32_t *next_record_handle);
+
+/** @brief Find (first) PDR record by PDR type
+ *
+ *  @param[in] repo - opaque pointer acting as a PDR repo handle
+ *  @param[in] pdr_type - PDR type number as per DSP0248
+ *  @param[in] curr_record - opaque pointer acting as a PDR record handle; if
+ *  not NULL, then search will begin from this record's next record
+ *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ *                        return
+ *  @param[out] size - *size will be size of PDR record
+ *
+ *  @return opaque pointer acting as PDR record handle, will be NULL if record
+ *  was not found
+ */
+const pldm_pdr_record *
+pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
+			     const pldm_pdr_record *curr_record, uint8_t **data,
+			     uint32_t *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PDR_H */
diff --git a/test/libpldm_pdr_test.cpp b/test/libpldm_pdr_test.cpp
new file mode 100644
index 0000000..fbae94a
--- /dev/null
+++ b/test/libpldm_pdr_test.cpp
@@ -0,0 +1,211 @@
+#include <array>
+
+#include "libpldm/pdr.h"
+#include "libpldm/platform.h"
+
+#include <gtest/gtest.h>
+
+TEST(PDRAccess, testInit)
+{
+    auto repo = pldm_pdr_init();
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 0);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), 0);
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRUpdate, testAdd)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint8_t, 10> data{};
+    auto handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), data.size());
+
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 2);
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 3);
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0xdeeddeed);
+    EXPECT_EQ(handle, 0xdeeddeed);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), data.size() * 4);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testGet)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint32_t, 10> in{100, 345, 3, 6, 89, 0, 11, 45, 23434, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in.data()), sizeof(in), 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in));
+    uint32_t size{};
+    uint32_t nextRecHdl{};
+    uint8_t* outData = nullptr;
+    auto hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    auto hdl2 = pldm_pdr_find_record(repo, 1, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, hdl2);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    hdl = pldm_pdr_find_record(repo, 0xdeaddead, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, nullptr);
+    EXPECT_EQ(size, 0);
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(outData, nullptr);
+    outData = nullptr;
+
+    std::array<uint32_t, 10> in2{1000, 3450, 30,  60,     890,
+                                 0,    110,  450, 234034, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 2);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 3);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 4);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in2) * 4);
+    hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 2);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+    hdl2 = pldm_pdr_find_record(repo, 1, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, hdl2);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 2);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 2, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 3);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 3, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 4);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 4, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testGetNext)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint32_t, 10> in{100, 345, 3, 6, 89, 0, 11, 45, 23434, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in.data()), sizeof(in), 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in));
+    uint32_t size{};
+    uint32_t nextRecHdl{};
+    uint8_t* outData = nullptr;
+    auto hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    std::array<uint32_t, 10> in2{1000, 3450, 30,  60,     890,
+                                 0,    110,  450, 234034, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 2);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 3);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 4);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in2) * 4);
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 3);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 4);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testFindByType)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint8_t, sizeof(pldm_pdr_hdr)> data{};
+    pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(data.data());
+    hdr->type = 1;
+    auto first = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 2;
+    auto second = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 3;
+    auto third = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 4;
+    auto fourth = pldm_pdr_add(repo, data.data(), data.size(), 0);
+
+    uint8_t* outData = nullptr;
+    uint32_t size{};
+    auto firstRec =
+        pldm_pdr_find_record_by_type(repo, 1, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, firstRec), first);
+    outData = nullptr;
+    auto secondRec =
+        pldm_pdr_find_record_by_type(repo, 2, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, secondRec), second);
+    outData = nullptr;
+    auto thirdRec =
+        pldm_pdr_find_record_by_type(repo, 3, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, thirdRec), third);
+    outData = nullptr;
+    auto fourthRec =
+        pldm_pdr_find_record_by_type(repo, 4, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, fourthRec), fourth);
+    outData = nullptr;
+    auto fifthRec =
+        pldm_pdr_find_record_by_type(repo, 5, nullptr, &outData, &size);
+    EXPECT_EQ(fifthRec, nullptr);
+    EXPECT_EQ(outData, nullptr);
+    EXPECT_EQ(size, 0);
+
+    auto rec =
+        pldm_pdr_find_record_by_type(repo, 3, secondRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), third);
+    outData = nullptr;
+    rec = pldm_pdr_find_record_by_type(repo, 4, secondRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), fourth);
+    outData = nullptr;
+    rec = pldm_pdr_find_record_by_type(repo, 2, firstRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), second);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
diff --git a/test/meson.build b/test/meson.build
index c32451b..644b7fd 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -31,7 +31,8 @@
   'pldmd_instanceid_test',
   'pldmd_registration_test',
   'pldm_utils_test',
-  'libpldmresponder_fru_test'
+  'libpldmresponder_fru_test',
+  'libpldm_pdr_test'
 ]
 
 if get_option('oem-ibm').enabled()