From 129893f6b398c644a14b98352c792cc3bc141072 Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:01:05 +0100 Subject: [PATCH 01/11] gh #98 updated ut_kvp_open --- src/ut_kvp.c | 70 +++++++++++++++++++++++++++-------------- tests/src/ut_test_kvp.c | 5 +++ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 1e57cef..994ddda 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -95,55 +95,79 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance) pInternal = NULL; } -ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName) +static bool is_url(const char *input) { - struct fy_node *node; - ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); + if (input == NULL) { + return false; + } + return (strncmp(input, "http://", 7) == 0 || strncmp(input, "https://", 8) == 0); +} - if (pInstance == NULL) +static struct fy_document* build_yaml_from_source(const char *fileNameOrUrl, bool isUrl) +{ + if (isUrl) { - return UT_KVP_STATUS_INVALID_INSTANCE; + char yaml[512]; + snprintf(yaml, sizeof(yaml), "include: %s\n", fileNameOrUrl); + return fy_document_build_from_string(NULL, (const char *)yaml, sizeof(yaml)); } - - if (fileName == NULL) + else { - UT_LOG_ERROR( "Invalid Param [fileName]" ); - return UT_KVP_STATUS_INVALID_PARAM; + if (access(fileNameOrUrl, F_OK) != 0) + { + UT_LOG_ERROR("[%s] cannot be accessed", fileNameOrUrl); + return NULL; + } + return fy_document_build_from_file(NULL, fileNameOrUrl); } +} + +ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileNameOrUrl) +{ + if (pInstance == NULL) + return UT_KVP_STATUS_INVALID_INSTANCE; - if (access(fileName, F_OK) != 0) + if (fileNameOrUrl == NULL) { - UT_LOG_ERROR("[%s] cannot be accesed", fileName); - return UT_KVP_STATUS_FILE_OPEN_ERROR; + UT_LOG_ERROR("Invalid Param [fileNameOrUrl]"); + return UT_KVP_STATUS_INVALID_PARAM; } - if(pInternal->fy_handle) + ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); + bool url = is_url(fileNameOrUrl); + + if (pInternal->fy_handle) { - merge_nodes(fy_document_root(pInternal->fy_handle), fy_document_root(fy_document_build_from_file(NULL, fileName))); + merge_nodes(fy_document_root(pInternal->fy_handle), fy_document_root(build_yaml_from_source(fileNameOrUrl, url))); } else { pInternal->fy_handle = fy_document_create(NULL); + if (pInternal->fy_handle == NULL) + { + UT_LOG_ERROR("Unable to create YAML handle"); + ut_kvp_close(pInstance); + return UT_KVP_STATUS_PARSING_ERROR; + } } - if (NULL == pInternal->fy_handle) + // Step 2: Build the actual srcDoc for processing + struct fy_document *srcDoc = build_yaml_from_source(fileNameOrUrl, url); + if (srcDoc == NULL) { - UT_LOG_ERROR("Unable to parse file/memory"); - ut_kvp_close( pInstance ); + UT_LOG_ERROR("Failed to build srcDoc for processing"); + ut_kvp_close(pInstance); return UT_KVP_STATUS_PARSING_ERROR; } - struct fy_document *srcDoc = fy_document_build_from_file(NULL, fileName); - - if(fy_document_resolve(srcDoc) != 0) + if (fy_document_resolve(srcDoc) != 0) { UT_LOG_ERROR("Error resolving document for anchors, aliases and merge keys"); ut_kvp_close(pInstance); return UT_KVP_STATUS_PARSING_ERROR; } - - node = process_node_copy(fy_document_root(srcDoc), pInternal->fy_handle, 0); - + + struct fy_node *node = process_node_copy(fy_document_root(srcDoc), pInternal->fy_handle, 0); if (node == NULL) { UT_LOG_ERROR("Unable to process node"); diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index 1b8da12..61989f7 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -42,6 +42,7 @@ #define KVP_VALID_TEST_SEQUENCE_INCLUDE_YAML "assets/include/sequence-include.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_YAML "assets/yaml_tags.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_IN_SEQUENCE_YAML "assets/yaml_tags_in_sequence.yaml" +#define KVP_VALID_TEST_URL_FILE "https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/2s.yaml" static ut_kvp_instance_t *gpMainTestInstance = NULL; static UT_test_suite_t *gpKVPSuite = NULL; @@ -129,6 +130,10 @@ void test_ut_kvp_open( void ) status = ut_kvp_open( pInstance, KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE ) - Positive"); + status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE); + UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + /* Test Destroy causes close this should work fine */ UT_LOG_STEP("ut_kvp_destroyInstance(1) - Positive"); ut_kvp_destroyInstance( pInstance ); From 2731cc3efc7b57b777c12cf6b326e84362394986 Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Wed, 8 Oct 2025 17:30:46 +0100 Subject: [PATCH 02/11] gh #98 updated the test --- src/ut_kvp.c | 11 ++++++----- tests/src/ut_test_kvp.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 994ddda..1a4bfd0 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -113,11 +113,6 @@ static struct fy_document* build_yaml_from_source(const char *fileNameOrUrl, boo } else { - if (access(fileNameOrUrl, F_OK) != 0) - { - UT_LOG_ERROR("[%s] cannot be accessed", fileNameOrUrl); - return NULL; - } return fy_document_build_from_file(NULL, fileNameOrUrl); } } @@ -136,6 +131,12 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileNameOrUrl) ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); bool url = is_url(fileNameOrUrl); + if ((access(fileNameOrUrl, F_OK) != 0) && url == 0) + { + UT_LOG_ERROR("[%s] cannot be accessed", fileNameOrUrl); + return UT_KVP_STATUS_FILE_OPEN_ERROR; + } + if (pInternal->fy_handle) { merge_nodes(fy_document_root(pInternal->fy_handle), fy_document_root(build_yaml_from_source(fileNameOrUrl, url))); diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index 61989f7..2963164 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -129,7 +129,7 @@ void test_ut_kvp_open( void ) UT_LOG_STEP("ut_kvp_open( pInstance, %s ) - Postive", KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); status = ut_kvp_open( pInstance, KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); - + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE ) - Positive"); status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); From 82d755c2490323a856769bfac7585bcf15f4d17c Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:02:57 +0100 Subject: [PATCH 03/11] gh #98 addressed review comments --- src/ut_kvp.c | 2 +- tests/src/ut_test_kvp.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 1a4bfd0..3b972f6 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -131,7 +131,7 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileNameOrUrl) ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); bool url = is_url(fileNameOrUrl); - if ((access(fileNameOrUrl, F_OK) != 0) && url == 0) + if (url == 0 && (access(fileNameOrUrl, F_OK) != 0)) { UT_LOG_ERROR("[%s] cannot be accessed", fileNameOrUrl); return UT_KVP_STATUS_FILE_OPEN_ERROR; diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index 2963164..c27d8f3 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -42,7 +42,7 @@ #define KVP_VALID_TEST_SEQUENCE_INCLUDE_YAML "assets/include/sequence-include.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_YAML "assets/yaml_tags.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_IN_SEQUENCE_YAML "assets/yaml_tags_in_sequence.yaml" -#define KVP_VALID_TEST_URL_FILE "https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/2s.yaml" +#define KVP_VALID_TEST_URL "https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/2s.yaml" static ut_kvp_instance_t *gpMainTestInstance = NULL; static UT_test_suite_t *gpKVPSuite = NULL; @@ -130,8 +130,8 @@ void test_ut_kvp_open( void ) status = ut_kvp_open( pInstance, KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); - UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE ) - Positive"); - status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL_FILE); + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL ) - Positive"); + status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); /* Test Destroy causes close this should work fine */ From 4d0dde5726dbd0056b770a086aa68cbd559e1df6 Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Thu, 16 Oct 2025 18:56:55 +0100 Subject: [PATCH 04/11] gh #98 addressed review comments --- include/ut_kvp.h | 2 +- src/ut_kvp.c | 89 +++++++++++++++++++++++------------- tests/src/ut_control_test.sh | 18 +++++++- tests/src/ut_test_kvp.c | 23 ++++++++-- 4 files changed, 92 insertions(+), 40 deletions(-) diff --git a/include/ut_kvp.h b/include/ut_kvp.h index 3924368..89b63c0 100644 --- a/include/ut_kvp.h +++ b/include/ut_kvp.h @@ -80,7 +80,7 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance); * @retval UT_KVP_STATUS_PARSING_ERROR - An error occurred while parsing the file contents. * @retval UT_KVP_STATUS_INVALID_INSTANCE - The provided `pInstance` is not a valid KVP instance. */ -ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName); +ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOrUrl); /**! * @brief Opens and parses a memory block read from a Key-Value Pair (KVP) file into a KVP instance. diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 3b972f6..bb63efc 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -97,31 +97,24 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance) static bool is_url(const char *input) { - if (input == NULL) { + if (input == NULL) + { return false; } return (strncmp(input, "http://", 7) == 0 || strncmp(input, "https://", 8) == 0); } -static struct fy_document* build_yaml_from_source(const char *fileNameOrUrl, bool isUrl) +ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOrUrl) { - if (isUrl) - { - char yaml[512]; - snprintf(yaml, sizeof(yaml), "include: %s\n", fileNameOrUrl); - return fy_document_build_from_string(NULL, (const char *)yaml, sizeof(yaml)); - } - else - { - return fy_document_build_from_file(NULL, fileNameOrUrl); - } -} + struct fy_node *node; -ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileNameOrUrl) -{ + // Validate KVP instance handle if (pInstance == NULL) + { return UT_KVP_STATUS_INVALID_INSTANCE; + } + // Validate fileNameOrUrl parameter if (fileNameOrUrl == NULL) { UT_LOG_ERROR("Invalid Param [fileNameOrUrl]"); @@ -129,46 +122,76 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileNameOrUrl) } ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); - bool url = is_url(fileNameOrUrl); - if (url == 0 && (access(fileNameOrUrl, F_OK) != 0)) + // Determine if input is a URL(e.g., http:// or https://) + bool bFilenameIsAUrl = is_url(fileNameOrUrl); + + // -------------------- Handle URL-based input ----------------------- + if(bFilenameIsAUrl == true) + { + char yamlLocal[UT_KVP_MAX_ELEMENT_SIZE]; + snprintf(yamlLocal, sizeof(yamlLocal), "include: %s\n", fileNameOrUrl); + + // Dynamically allocate, since fy_document_build_from_malloc_string() + // will take ownership and free it internally. + char *yaml = strdup(yamlLocal); + + if (!yaml) + { + UT_LOG_ERROR("Memory allocation failed for yaml"); + return UT_KVP_STATUS_PARSING_ERROR; + } + + // Pass the dynamically allocated YAML string to openMemory() for parsing + return ut_kvp_openMemory(pInstance, yaml, strlen(yaml)); + } + + // ---------------------- Handle file-based input ---------------------- + if (strncmp(fileNameOrUrl, "file://", 7) == 0) + { + // Skip "file://" + fileNameOrUrl = fileNameOrUrl + 7; + } + + // Verify that the file is accessible + if (access(fileNameOrUrl, F_OK) != 0) { UT_LOG_ERROR("[%s] cannot be accessed", fileNameOrUrl); return UT_KVP_STATUS_FILE_OPEN_ERROR; } - if (pInternal->fy_handle) + // If there’s already a handle, merge the new document into existing YAML + if(pInternal->fy_handle) { - merge_nodes(fy_document_root(pInternal->fy_handle), fy_document_root(build_yaml_from_source(fileNameOrUrl, url))); + merge_nodes(fy_document_root(pInternal->fy_handle), fy_document_root(fy_document_build_from_file(NULL, fileNameOrUrl))); } else { + // Otherwise, create a new YAML document handle pInternal->fy_handle = fy_document_create(NULL); - if (pInternal->fy_handle == NULL) - { - UT_LOG_ERROR("Unable to create YAML handle"); - ut_kvp_close(pInstance); - return UT_KVP_STATUS_PARSING_ERROR; - } } - // Step 2: Build the actual srcDoc for processing - struct fy_document *srcDoc = build_yaml_from_source(fileNameOrUrl, url); - if (srcDoc == NULL) + // Ensure the handle is valid + if (NULL == pInternal->fy_handle) { - UT_LOG_ERROR("Failed to build srcDoc for processing"); - ut_kvp_close(pInstance); + UT_LOG_ERROR("Unable to parse file/memory"); + ut_kvp_close( pInstance ); return UT_KVP_STATUS_PARSING_ERROR; } - if (fy_document_resolve(srcDoc) != 0) + // Build a source YAML document from the file + struct fy_document *srcDoc = fy_document_build_from_file(NULL, fileNameOrUrl); + + if(fy_document_resolve(srcDoc) != 0) { UT_LOG_ERROR("Error resolving document for anchors, aliases and merge keys"); ut_kvp_close(pInstance); return UT_KVP_STATUS_PARSING_ERROR; } - - struct fy_node *node = process_node_copy(fy_document_root(srcDoc), pInternal->fy_handle, 0); + + // Process and copy nodes from source document into internal handle + node = process_node_copy(fy_document_root(srcDoc), pInternal->fy_handle, 0); + if (node == NULL) { UT_LOG_ERROR("Unable to process node"); diff --git a/tests/src/ut_control_test.sh b/tests/src/ut_control_test.sh index e52e322..18e2d7c 100755 --- a/tests/src/ut_control_test.sh +++ b/tests/src/ut_control_test.sh @@ -27,4 +27,20 @@ cd "$(dirname "$0")" export LD_LIBRARY_PATH=/usr/lib:/lib:/home/root:${MY_DIR} -./ut_control_test $@ +# Start HTTP server in background +python3 -m http.server 8000 & +HTTP_PID=$! + +# Register cleanup trap to stop HTTP server on exit +trap ' + kill $HTTP_PID 2>/dev/null || true + wait $HTTP_PID 2>/dev/null || true +' EXIT + +# Run test +./ut_control_test "$@" +UT_STATUS=$? + +# Exit with same status as UT test +exit $UT_STATUS + diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index c27d8f3..fe55d89 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -42,7 +42,9 @@ #define KVP_VALID_TEST_SEQUENCE_INCLUDE_YAML "assets/include/sequence-include.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_YAML "assets/yaml_tags.yaml" #define KVP_VALID_TEST_RESOLVE_YAML_TAGS_IN_SEQUENCE_YAML "assets/yaml_tags_in_sequence.yaml" -#define KVP_VALID_TEST_URL "https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/2s.yaml" +#define KVP_VALID_TEST_URL_HTTPS "https://raw.githubusercontent.com/rdkcentral/ut-control/main/tests/src/assets/include/2s.yaml" +#define KVP_VALID_TEST_URI_HTTP "http://localhost:8000/assets/yaml_tags.yaml" +#define KVP_VALID_TEST_URI_FILE "file://assets/yaml_tags.yaml" static ut_kvp_instance_t *gpMainTestInstance = NULL; static UT_test_suite_t *gpKVPSuite = NULL; @@ -126,13 +128,24 @@ void test_ut_kvp_open( void ) status = ut_kvp_open( pInstance, KVP_VALID_TEST_YAML_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL_HTTPS ) - Positive"); + status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL_HTTPS); + printf("\nKVP Status = %d", status); + UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URI_HTTP ) - Positive"); + status = ut_kvp_open( pInstance, KVP_VALID_TEST_URI_HTTP); + printf("\nKVP Status = %d", status); + UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + + UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URI_FILE ) - Positive"); + status = ut_kvp_open( pInstance, KVP_VALID_TEST_URI_FILE); + printf("\nKVP Status = %d", status); + UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); + UT_LOG_STEP("ut_kvp_open( pInstance, %s ) - Postive", KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); status = ut_kvp_open( pInstance, KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); - - UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL ) - Positive"); - status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL); - UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); /* Test Destroy causes close this should work fine */ UT_LOG_STEP("ut_kvp_destroyInstance(1) - Positive"); From 0540b76f88dbee426ea5e624f2f11b80a18371da Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:28:18 +0530 Subject: [PATCH 05/11] gh #98 added free for string buffer --- src/ut_kvp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 667298a..9a6be4a 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -143,7 +143,9 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr } // Pass the dynamically allocated YAML string to openMemory() for parsing - return ut_kvp_openMemory(pInstance, yaml, strlen(yaml)); + ut_kvp_status_t status = ut_kvp_openMemory(pInstance, yaml, strlen(yaml)); + free(yaml); + return status; } // ---------------------- Handle file-based input ---------------------- @@ -1210,4 +1212,4 @@ static const void *find_pattern_from_buffer(const void *buffer, size_t bufferLen } return NULL; -} \ No newline at end of file +} From 679e6f36225f7c4462895600352784980977f9fd Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:29:30 +0530 Subject: [PATCH 06/11] gh #98 updated param name of ut_kvp_open() in description --- include/ut_kvp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ut_kvp.h b/include/ut_kvp.h index 359ebf0..3ba4e77 100644 --- a/include/ut_kvp.h +++ b/include/ut_kvp.h @@ -71,7 +71,7 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance); * This function opens the specified KVP file, reads its contents, and parses the key-value pairs into the given KVP instance. * * @param[in] pInstance - Handle to the KVP instance where the parsed data will be stored. - * @param[in] fileName - Null-terminated string containing the path to the KVP file. + * @param[in] fileNameOrUrl - Null-terminated string containing the path to the KVP file. * * @returns Status of the operation (`ut_kvp_status_t`): * @retval UT_KVP_STATUS_SUCCESS - The file was opened and parsed successfully. @@ -269,4 +269,4 @@ unsigned char* ut_kvp_getDataBytes(ut_kvp_instance_t *pInstance, const char *psz } #endif -#endif /* __UT_KVP_H__ */ \ No newline at end of file +#endif /* __UT_KVP_H__ */ From 854e763529e906081efb809e087eb0cc1e949e82 Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Thu, 30 Oct 2025 13:05:04 +0000 Subject: [PATCH 07/11] gh #98 addressed review comments --- src/ut_kvp.c | 61 ++++++++++++++++++++++++++++------------- tests/src/ut_test_kvp.c | 2 +- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 0c16b82..d78148e 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -37,6 +37,15 @@ ut_kvp_instance_t *gKVP_Instance = NULL; #define UT_KVP_MAGIC (0xdeadbeef) #define UT_KVP_MAX_INCLUDE_DEPTH 5 +#define UT_KVP_HTTPS_PREFIX "https://" +#define UT_KVP_HTTP_PREFIX "http://" +#define UT_KVP_FILE_PREFIX "file://" + +// Automatically calculate lengths by subtracting the '\0' null terminator +#define UT_KVP_HTTPS_PREFIX_LEN (sizeof(UT_KVP_HTTPS_PREFIX) - 1) +#define UT_KVP_HTTP_PREFIX_LEN (sizeof(UT_KVP_HTTP_PREFIX) - 1) +#define UT_KVP_FILE_PREFIX_LEN (sizeof(UT_KVP_FILE_PREFIX) - 1) + typedef struct { uint32_t magic; @@ -101,7 +110,21 @@ static bool is_url(const char *input) { return false; } - return (strncmp(input, "http://", 7) == 0 || strncmp(input, "https://", 8) == 0); + + // Check for http:// + if (strncmp(input, UT_KVP_HTTP_PREFIX, UT_KVP_HTTP_PREFIX_LEN) == 0) + { + return true; + } + + // Check for https:// + if (strncmp(input, UT_KVP_HTTPS_PREFIX, UT_KVP_HTTPS_PREFIX_LEN) == 0) + { + return true; + } + + // No matches found + return false; } ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOrUrl) @@ -117,8 +140,8 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr // Validate fileNameOrUrl parameter if (fileNameOrUrl == NULL) { - UT_LOG_ERROR("Invalid Param [fileNameOrUrl]"); - return UT_KVP_STATUS_INVALID_PARAM; + UT_LOG_ERROR("NULL PARAM [fileNameOrUrl]"); + return UT_KVP_STATUS_NULL_PARAM; } ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); @@ -129,30 +152,29 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr // -------------------- Handle URL-based input ----------------------- if(bFilenameIsAUrl == true) { - char yamlLocal[UT_KVP_MAX_ELEMENT_SIZE]; - snprintf(yamlLocal, sizeof(yamlLocal), "include: %s\n", fileNameOrUrl); - - // Dynamically allocate, since fy_document_build_from_malloc_string() - // will take ownership and free it internally. - char *yaml = strdup(yamlLocal); - - if (!yaml) + char *pYaml = NULL; + + pYaml = malloc(UT_KVP_MAX_ELEMENT_SIZE); + + snprintf(pYaml, UT_KVP_MAX_ELEMENT_SIZE, "include: %s\n", fileNameOrUrl); + + if ( pYaml == NULL ) { - UT_LOG_ERROR("Memory allocation failed for yaml"); - return UT_KVP_STATUS_PARSING_ERROR; + UT_LOG_ERROR("Malloc was not able to provide memory\n"); + return UT_KVP_STATUS_NULL_PARAM; } - + // Pass the dynamically allocated YAML string to openMemory() for parsing - ut_kvp_status_t status = ut_kvp_openMemory(pInstance, yaml, strlen(yaml)); - free(yaml); + ut_kvp_status_t status = ut_kvp_openMemory(pInstance, pYaml, strlen(pYaml)); + free(pYaml); return status; } - // ---------------------- Handle file-based input ---------------------- - if (strncmp(fileNameOrUrl, "file://", 7) == 0) + // Handle file-based input + if (strncmp(fileNameOrUrl, UT_KVP_FILE_PREFIX, UT_KVP_FILE_PREFIX_LEN) == 0) { // Skip "file://" - fileNameOrUrl = fileNameOrUrl + 7; + fileNameOrUrl = fileNameOrUrl + UT_KVP_FILE_PREFIX_LEN; } // Verify that the file is accessible @@ -188,6 +210,7 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr { UT_LOG_ERROR("Error resolving document for anchors, aliases and merge keys"); ut_kvp_close(pInstance); + fy_document_destroy(srcDoc); return UT_KVP_STATUS_PARSING_ERROR; } diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index ceedf6d..cf750b9 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -111,7 +111,7 @@ void test_ut_kvp_open( void ) /* Negative Read Test, NULL PARAM */ UT_LOG_STEP("ut_kvp_open( pInstance, NULL ) - Negative"); status = ut_kvp_open( pInstance, NULL); - UT_ASSERT( status == UT_KVP_STATUS_INVALID_PARAM ); + UT_ASSERT( status == UT_KVP_STATUS_NULL_PARAM ); /* Filename doesn't exist */ UT_LOG_STEP("ut_kvp_open( pInstance, %s - filename doesn't exist ) - Negative", KVP_VALID_TEST_NO_FILE); From 37babe10aaaadc790442eeba855f7cb04bc6d2db Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Thu, 30 Oct 2025 13:36:41 +0000 Subject: [PATCH 08/11] gh #98 updated ut_kvp.c --- include/ut_kvp.h | 2 +- src/ut_kvp.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/ut_kvp.h b/include/ut_kvp.h index 3ba4e77..89a1518 100644 --- a/include/ut_kvp.h +++ b/include/ut_kvp.h @@ -71,7 +71,7 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance); * This function opens the specified KVP file, reads its contents, and parses the key-value pairs into the given KVP instance. * * @param[in] pInstance - Handle to the KVP instance where the parsed data will be stored. - * @param[in] fileNameOrUrl - Null-terminated string containing the path to the KVP file. + * @param[in] fileNameOrUrl - Null-terminated string containing the path to the KVP file/URL. * * @returns Status of the operation (`ut_kvp_status_t`): * @retval UT_KVP_STATUS_SUCCESS - The file was opened and parsed successfully. diff --git a/src/ut_kvp.c b/src/ut_kvp.c index d78148e..21f591c 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -131,8 +131,10 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr { struct fy_node *node; + ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); + // Validate KVP instance handle - if (pInstance == NULL) + if (pInternal == NULL) { return UT_KVP_STATUS_INVALID_INSTANCE; } @@ -144,26 +146,24 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr return UT_KVP_STATUS_NULL_PARAM; } - ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); - // Determine if input is a URL(e.g., http:// or https://) bool bFilenameIsAUrl = is_url(fileNameOrUrl); - // -------------------- Handle URL-based input ----------------------- + // Handle URL-based input if(bFilenameIsAUrl == true) { char *pYaml = NULL; pYaml = malloc(UT_KVP_MAX_ELEMENT_SIZE); - snprintf(pYaml, UT_KVP_MAX_ELEMENT_SIZE, "include: %s\n", fileNameOrUrl); - if ( pYaml == NULL ) { UT_LOG_ERROR("Malloc was not able to provide memory\n"); return UT_KVP_STATUS_NULL_PARAM; } + snprintf(pYaml, UT_KVP_MAX_ELEMENT_SIZE, "include: %s\n", fileNameOrUrl); + // Pass the dynamically allocated YAML string to openMemory() for parsing ut_kvp_status_t status = ut_kvp_openMemory(pInstance, pYaml, strlen(pYaml)); free(pYaml); From 889d5d566d51058357b44a25916033487986ebc4 Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:19:31 +0000 Subject: [PATCH 09/11] gh #98 addressed copilot comments --- src/ut_kvp.c | 2 +- tests/src/ut_test_kvp.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 21f591c..6b7d0b1 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -159,7 +159,7 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, const char *fileNameOr if ( pYaml == NULL ) { UT_LOG_ERROR("Malloc was not able to provide memory\n"); - return UT_KVP_STATUS_NULL_PARAM; + return UT_KVP_STATUS_PARSING_ERROR; } snprintf(pYaml, UT_KVP_MAX_ELEMENT_SIZE, "include: %s\n", fileNameOrUrl); diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index cf750b9..f004327 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -130,17 +130,14 @@ void test_ut_kvp_open( void ) UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URL_HTTPS ) - Positive"); status = ut_kvp_open( pInstance, KVP_VALID_TEST_URL_HTTPS); - printf("\nKVP Status = %d", status); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URI_HTTP ) - Positive"); status = ut_kvp_open( pInstance, KVP_VALID_TEST_URI_HTTP); - printf("\nKVP Status = %d", status); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); UT_LOG_STEP("ut_kvp_open( pInstance, KVP_VALID_TEST_URI_FILE ) - Positive"); status = ut_kvp_open( pInstance, KVP_VALID_TEST_URI_FILE); - printf("\nKVP Status = %d", status); UT_ASSERT( status == UT_KVP_STATUS_SUCCESS ); UT_LOG_STEP("ut_kvp_open( pInstance, %s ) - Postive", KVP_VALID_TEST_NOT_VALID_YAML_FORMATTED_FILE); From 9a662947a6ad97aaa80c5880179e6946fa6b845a Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:59:57 +0000 Subject: [PATCH 10/11] gh #98 updated the header file --- include/ut_kvp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ut_kvp.h b/include/ut_kvp.h index 89a1518..3077450 100644 --- a/include/ut_kvp.h +++ b/include/ut_kvp.h @@ -76,7 +76,7 @@ void ut_kvp_destroyInstance(ut_kvp_instance_t *pInstance); * @returns Status of the operation (`ut_kvp_status_t`): * @retval UT_KVP_STATUS_SUCCESS - The file was opened and parsed successfully. * @retval UT_KVP_STATUS_FILE_OPEN_ERROR - The file could not be opened. - * @retval UT_KVP_STATUS_INVALID_PARAM - One or more parameters are invalid (e.g., null pointer). + * @retval UT_KVP_STATUS_NULL_PARAM - One or more parameters are NULL (e.g., null pointer). * @retval UT_KVP_STATUS_PARSING_ERROR - An error occurred while parsing the file contents. * @retval UT_KVP_STATUS_INVALID_INSTANCE - The provided `pInstance` is not a valid KVP instance. */ From 60483b50e512dd16a0f4bbc90059c89f23d7d5bf Mon Sep 17 00:00:00 2001 From: KarthikeyanR470 <179679359+KarthikeyanR470@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:18:54 +0530 Subject: [PATCH 11/11] gh #98 Updated httpserver up logic in ut_control_test.sh --- tests/src/ut_control_test.sh | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/src/ut_control_test.sh b/tests/src/ut_control_test.sh index ab3b896..74c8069 100755 --- a/tests/src/ut_control_test.sh +++ b/tests/src/ut_control_test.sh @@ -27,19 +27,26 @@ cd "$(dirname "$0")" export LD_LIBRARY_PATH=/usr/lib:/lib:/home/root:${MY_DIR} -# Start HTTP server in background -python3 -m http.server 8000 & -HTTP_PID=$! - -# Register cleanup trap to stop HTTP server on exit -trap ' - kill $HTTP_PID 2>/dev/null || true - wait $HTTP_PID 2>/dev/null || true -' EXIT +HTTP_PORT=8000 +HTTP_PID="" + +# Check if HTTP server is already running +if ! lsof -iTCP:${HTTP_PORT} -sTCP:LISTEN >/dev/null 2>&1; then + python3 -m http.server ${HTTP_PORT} & + HTTP_PID=$! +fi + +# Cleanup only if this script started the server +cleanup() { + if [[ -n "$HTTP_PID" ]]; then + kill "$HTTP_PID" 2>/dev/null || true + wait "$HTTP_PID" 2>/dev/null || true + fi +} +trap cleanup EXIT # Run test -./ut_control_test "$@" +LSAN_OPTIONS="suppressions=../../lsan.supp print_suppressions=1" ./ut_control_test "$@" UT_STATUS=$? -# Exit with same status as UT test -exit $UT_STATUS \ No newline at end of file +exit $UT_STATUS