From ae7c18869f34098c4d091e89043c59be9e3ef85b Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:39:42 +0000 Subject: [PATCH 1/9] Add gh #66 : Adding first level changes for GET Request support in ut-control --- src/ut_control_plane.c | 145 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 7 deletions(-) diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index e682b4d..b0561c1 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -288,26 +288,155 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void return 0; } #else + static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { cp_message_t msg; - ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t* )lws_context_user(lws_get_context(wsi)); + ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)lws_context_user(lws_get_context(wsi)); struct per_session_data__http *perSessionData = (struct per_session_data__http *)user; switch (reason) { - case LWS_CALLBACK_HTTP: { + + case LWS_CALLBACK_HTTP: + { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); - char *requested_uri = (char *)in; + char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI + char query_string[256] = {0}; // Buffer for the query string + char accept_header[256] = {0}; // Buffer for the Accept header + char response[1024] = {0}; // Buffer for the response + char *key = NULL; + char *value = NULL; + unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body + unsigned char *p = buffer + LWS_PRE; // Pointer to start of usable buffer space + unsigned char *end = buffer + sizeof(buffer); // Pointer to end of buffer + + + UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri); + + // Handle GET request for /api/getKVP + if (strcmp(requested_uri, "/api/getKVP") == 0) + { + // Extract the query string (if any) + if (lws_hdr_copy(wsi, query_string, sizeof(query_string), WSI_TOKEN_HTTP_URI_ARGS) > 0) + { + UT_CONTROL_PLANE_DEBUG("Query String: %s\n", query_string); + + // Parse key-value pairs from the query string + key = strtok(query_string, "="); + value = strtok(NULL, "&"); + + if (key && value) + { + UT_CONTROL_PLANE_DEBUG("Received GET parameter: %s = %s\n", key, value); + } + } + + // Extract the Accept header + if (lws_hdr_copy(wsi, accept_header, sizeof(accept_header), WSI_TOKEN_HTTP_ACCEPT) > 0) + { + UT_CONTROL_PLANE_DEBUG("Accept Header: %s\n", accept_header); + } + else + { + UT_CONTROL_PLANE_ERROR("Missing Accept header\n"); + lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + return -1; // Missing Accept header + } + + // Check for valid key parameter + if (key && strcmp(key, "key") == 0) + { + if (strcmp(value, "json") == 0 && strncmp(accept_header, "application/json", 16) == 0) + { + // Format pInternal as JSON + snprintf(response, sizeof(response), + "{\"field1\": \"%s\", \"field2\": %d, \"field3\": \"%s\"}", + "value1", 123, "value3"); + + // Add HTTP headers + if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) + { + return -1; // Failed to add headers + } + + // Finalize headers + if (lws_finalize_http_header(wsi, &p, end) < 0) + { + return -1; // Failed to finalize headers + } + + // Write headers + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { + return -1; // Failed to write headers + } + + // Write body + if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) + { + return -1; // Failed to write body + } + + return 1; // HTTP request handled + } + else if (strcmp(value, "yaml") == 0 && strncmp(accept_header, "application/x-yaml", 18) == 0) + { + // Format pInternal as YAML + snprintf(response, sizeof(response), + "field1: %s\nfield2: %d\nfield3: %s\n", + "value1", 123, "value3"); + + // Add HTTP headers + if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) + { + return -1; // Failed to add headers + } + + // Finalize headers + if (lws_finalize_http_header(wsi, &p, end) < 0) + { + return -1; // Failed to finalize headers + } + + // Write headers + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { + return -1; // Failed to write headers + } + + // Write body + if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) + { + return -1; // Failed to write body + } + + return 1; // HTTP request handled + } + else + { + UT_CONTROL_PLANE_ERROR("Invalid key value or unsupported Accept header\n"); + lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + return -1; + } + } + else + { + UT_CONTROL_PLANE_ERROR("Missing or invalid key parameter\n"); + lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + return -1; + } + } + // Handle POST request for /api/postKVP if (strcmp(requested_uri, "/api/postKVP") == 0) { lws_callback_on_writable(wsi); - return 0; + return 0; // Let the body handling process continue } + break; } - case LWS_CALLBACK_HTTP_BODY: { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); @@ -322,6 +451,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void else { // POST data too large + UT_CONTROL_PLANE_ERROR("POST data too large\n"); return -1; } } @@ -351,12 +481,13 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void // lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP); return 1; // HTTP request handled } + break; } default: break; - } - return 0; + } + return 0; } #endif From f62d964de9b76f4276128352d2044b5435edd950 Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:28:53 +0000 Subject: [PATCH 2/9] Add gh #66 : Added function in KVP to retreive data based on type KVP now has a function which emits data in either json or yaml based on users demand. Also added tests to check the function Added curl clients to test GET Requests. --- .vscode/settings.json | 9 +- include/ut_kvp.h | 10 ++ src/ut_control_plane.c | 135 +++++++++++++++--- src/ut_kvp.c | 43 ++++++ tests/src/ut_test_control_plane.c | 2 +- tests/src/ut_test_kvp.c | 29 ++++ .../curl-get-client-json-incorrect.sh | 1 + .../websocket-clients/curl-get-client-json.sh | 1 + .../curl-get-client-no-header.sh | 1 + .../curl-get-client-yaml-incorrect.sh | 1 + .../websocket-clients/curl-get-client-yaml.sh | 1 + ...t-binary.sh => curl-push-client-binary.sh} | 0 ...lient-json.sh => curl-push-client-json.sh} | 0 ...lient-yaml.sh => curl-push-client-yaml.sh} | 0 .../test_script_for_curl_request.sh | 57 ++++++++ 15 files changed, 266 insertions(+), 24 deletions(-) create mode 100755 tests/websocket-clients/curl-get-client-json-incorrect.sh create mode 100755 tests/websocket-clients/curl-get-client-json.sh create mode 100755 tests/websocket-clients/curl-get-client-no-header.sh create mode 100755 tests/websocket-clients/curl-get-client-yaml-incorrect.sh create mode 100755 tests/websocket-clients/curl-get-client-yaml.sh rename tests/websocket-clients/{curl-client-binary.sh => curl-push-client-binary.sh} (100%) rename tests/websocket-clients/{curl-client-json.sh => curl-push-client-json.sh} (100%) rename tests/websocket-clients/{curl-client-yaml.sh => curl-push-client-yaml.sh} (100%) create mode 100755 tests/websocket-clients/test_script_for_curl_request.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index c7554ad..bf1564f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -64,7 +64,14 @@ "ut_control_plane.h": "c", "ut.h": "c", "ut_log.h": "c", - "tuple": "c" + "tuple": "c", + "array": "c", + "compare": "c", + "functional": "c", + "type_traits": "c", + "utility": "c", + "istream": "c", + "ostream": "c" }, "cmake.configureOnOpen": true } \ No newline at end of file diff --git a/include/ut_kvp.h b/include/ut_kvp.h index 3924368..31d4597 100644 --- a/include/ut_kvp.h +++ b/include/ut_kvp.h @@ -254,6 +254,16 @@ uint32_t ut_kvp_getListCount( ut_kvp_instance_t *pInstance, const char *pszKey); */ unsigned char* ut_kvp_getDataBytes(ut_kvp_instance_t *pInstance, const char *pszKey, int *size); +/** + * @brief Get the data block from the instance based on the type requested by user. + * User to free the instance where the data is invalid, no output will be provided + * Also caller needs to ensure, that they free the pointer to the data block + * + * @param pInstance - pointer to the KVP instance + * @param pszType - type of data to be retrieved. Currently supported types are "json" and "yaml" + */ +char* ut_kvp_getDataOfType( ut_kvp_instance_t *pInstance, const char *pszType ); + /* TODO: * - Implement functions for getting signed integer values (`ut_kvp_getInt8Field`, `ut_kvp_getInt16Field`, `ut_kvp_getInt32Field`, *`ut_kvp_getInt64Field` diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index b0561c1..38ab7ed 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -289,6 +289,69 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void } #else +static char* create_response(ut_cp_instance_internal_t *pInternal, const char* key, const char* type) +{ + ut_kvp_instance_t *pkvpInstance = NULL; + ut_kvp_status_t status; + char result_kvp[UT_KVP_MAX_ELEMENT_SIZE] = {0xff}; + char* response = NULL; + + for (uint32_t i = 0; i < pInternal->callback_entry_index; i++) + { + CallbackEntry_t entry = pInternal->callbackEntryList[i]; + void *userData = malloc(strlen(entry.userData) + 1); // +1 for null terminator + if (userData == NULL) + { + UT_CONTROL_PLANE_ERROR("Memory allocation failed\n"); + return NULL; // Handle memory allocation failure + } + memcpy(userData, entry.userData, strlen(entry.userData) + 1); + + pkvpInstance = ut_kvp_createInstance(); + + /* Note: userData data will be freed by the destoryInstance() function */ + status = ut_kvp_openMemory(pkvpInstance, userData, strlen(entry.userData)); + if (status != UT_KVP_STATUS_SUCCESS) + { + UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n"); + ut_kvp_destroyInstance(pkvpInstance); + return NULL; + } + if (UT_KVP_STATUS_SUCCESS == ut_kvp_getStringField(pkvpInstance, key, result_kvp, UT_KVP_MAX_ELEMENT_SIZE)) + { + response = ut_kvp_getDataOfType(pkvpInstance, type); + } + ut_kvp_destroyInstance(pkvpInstance); + } + + return response; +} + +// Helper function to send error response +static int send_error_response(struct lws *wsi, int status, const char *content_type, const char *body) +{ + unsigned char buffer[LWS_PRE + 1024]; + unsigned char *p = buffer + LWS_PRE, *end = buffer + sizeof(buffer); + + // Add HTTP headers + if (lws_add_http_common_headers(wsi, status, content_type, strlen(body), &p, end) < 0) + return -1; + + // Finalize headers + if (lws_finalize_http_header(wsi, &p, end) < 0) + return -1; + + // Write headers + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + return -1; + + // Write body + if (lws_write(wsi, (unsigned char *)body, strlen(body), LWS_WRITE_HTTP_FINAL) < 0) + return -1; + + return 0; +} + static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { cp_message_t msg; @@ -305,9 +368,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI char query_string[256] = {0}; // Buffer for the query string char accept_header[256] = {0}; // Buffer for the Accept header - char response[1024] = {0}; // Buffer for the response + char *response = NULL; char *key = NULL; - char *value = NULL; unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body unsigned char *p = buffer + LWS_PRE; // Pointer to start of usable buffer space unsigned char *end = buffer + sizeof(buffer); // Pointer to end of buffer @@ -323,15 +385,24 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void { UT_CONTROL_PLANE_DEBUG("Query String: %s\n", query_string); - // Parse key-value pairs from the query string - key = strtok(query_string, "="); - value = strtok(NULL, "&"); - - if (key && value) + // Directly look for the "key=" prefix in the query string + char *key_param = strstr(query_string, "key="); + if (key_param != NULL) + { + key = key_param + 4; // Extract the value part (skip "key=") + UT_CONTROL_PLANE_DEBUG("Parsed Query Parameter: key=%s\n", key); + } + else { - UT_CONTROL_PLANE_DEBUG("Received GET parameter: %s = %s\n", key, value); + UT_CONTROL_PLANE_ERROR("Query parameter 'key' not found\n"); + key = NULL; // Ensure key is NULL if not found } } + else + { + UT_CONTROL_PLANE_ERROR("Failed to extract query string\n"); + key = NULL; // Ensure key is NULL if query string is absent + } // Extract the Accept header if (lws_hdr_copy(wsi, accept_header, sizeof(accept_header), WSI_TOKEN_HTTP_ACCEPT) > 0) @@ -341,19 +412,27 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void else { UT_CONTROL_PLANE_ERROR("Missing Accept header\n"); - lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); - return -1; // Missing Accept header + const char *error_response = "{\"error\": \"Missing Accept header\"}"; + if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0) + return -1; + return -1; } // Check for valid key parameter - if (key && strcmp(key, "key") == 0) + if (key) { - if (strcmp(value, "json") == 0 && strncmp(accept_header, "application/json", 16) == 0) + if (strncmp(accept_header, "application/json", 16) == 0) { - // Format pInternal as JSON - snprintf(response, sizeof(response), - "{\"field1\": \"%s\", \"field2\": %d, \"field3\": \"%s\"}", - "value1", 123, "value3"); + response = create_response(pInternal, key, "json"); + + if (response == NULL) + { + UT_CONTROL_PLANE_ERROR("Failed to create response\n"); + const char *error_response = "{\"error\": \"Internal Server Error\"}"; + if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/json", error_response) < 0) + return -1; + return -1; + } // Add HTTP headers if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) @@ -379,14 +458,22 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void return -1; // Failed to write body } + free(response); + return 1; // HTTP request handled } - else if (strcmp(value, "yaml") == 0 && strncmp(accept_header, "application/x-yaml", 18) == 0) + else if (strncmp(accept_header, "application/x-yaml", 18) == 0) { - // Format pInternal as YAML - snprintf(response, sizeof(response), - "field1: %s\nfield2: %d\nfield3: %s\n", - "value1", 123, "value3"); + response = create_response(pInternal, key, "yaml"); + + if (response == NULL) + { + UT_CONTROL_PLANE_ERROR("Failed to create response\n"); + const char *error_response = "error: Internal Server Error\n"; + if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/x-yaml", error_response) < 0) + return -1; + return -1; + } // Add HTTP headers if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) @@ -412,12 +499,16 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void return -1; // Failed to write body } + free(response); + return 1; // HTTP request handled } else { UT_CONTROL_PLANE_ERROR("Invalid key value or unsupported Accept header\n"); - lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + const char *error_response = "{\"error\": \"Unsupported Accept header or invalid type\"}"; + if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0) + return -1; return -1; } } diff --git a/src/ut_kvp.c b/src/ut_kvp.c index 7fef9fa..b8324a6 100644 --- a/src/ut_kvp.c +++ b/src/ut_kvp.c @@ -763,6 +763,49 @@ unsigned char* ut_kvp_getDataBytes(ut_kvp_instance_t *pInstance, const char *psz return output_bytes; } +char* ut_kvp_getDataOfType( ut_kvp_instance_t *pInstance, const char *pszType ) +{ + ut_kvp_instance_internal_t *pInternal = validateInstance(pInstance); + char *kvp_yaml_output = NULL; + + if (pInternal == NULL) + { + return NULL; + } + + if ( pInternal->fy_handle == NULL) + { + return NULL; + } + + if (pszType == NULL) + { + UT_LOG_ERROR("Invalid Param - type"); + return NULL; + } + + if (strncmp(pszType, "json", 4) == 0) + { + kvp_yaml_output = fy_emit_document_to_string(pInternal->fy_handle, FYECF_MODE_JSON); + } + else if (strncmp(pszType, "yaml", 4) == 0) + { + kvp_yaml_output = fy_emit_document_to_string(pInternal->fy_handle, FYECF_DEFAULT); + } + else + { + UT_LOG_ERROR("Invalid type"); + return NULL; + } + + if (kvp_yaml_output == NULL) + { + UT_LOG_ERROR("Failed to emit YAML document\n"); + return NULL; + } + return kvp_yaml_output; +} + /** Static Functions */ static ut_kvp_instance_internal_t *validateInstance(ut_kvp_instance_t *pInstance) { diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 93653b6..f1607c8 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -276,7 +276,7 @@ void run_client_function() UT_LOG("Please Run the command `./python-client-send-json.py or/& ./python-client-send-yaml.py` from another terminal and press return;'\n"); UT_LOG("In order to pass the test you need to run each of the python scripts'\n"); #else - UT_LOG("Please Run the command `./curl-client-json.sh or/& ./curl-client-yaml.sh or/& ./curl-client-binary.sh` from another terminal and press return;'\n"); + UT_LOG("Please Run the command `./curl-requests-script.sh` or `test_script_for_curl_request.sh` from another terminal and press return;'\n"); UT_LOG("In order to pass the test you need to run each of the curl scripts'\n"); #endif diff --git a/tests/src/ut_test_kvp.c b/tests/src/ut_test_kvp.c index 939a9d5..bc330b6 100644 --- a/tests/src/ut_test_kvp.c +++ b/tests/src/ut_test_kvp.c @@ -915,6 +915,33 @@ static void create_delete_kvp_memory_instance_for_given_file(const char* filenam ut_kvp_destroyInstance( pInstance ); } +void test_ut_kvp_getDataOfTypeJson() +{ + char* jsonData = ut_kvp_getDataOfType(gpMainTestInstance, "json"); + if(jsonData != NULL) + { + // Print the emitted KVP string + printf("%s\n", jsonData); + + // Free the emitted KVP string + free(jsonData); + } +} + +void test_ut_kvp_getDataOfTypeYaml() +{ + char* yamlData = ut_kvp_getDataOfType(gpMainTestInstance, "yaml"); + if(yamlData != NULL) + { + // Print the emitted KVP string + printf("%s\n", yamlData); + + // Free the emitted KVP string + free(yamlData); + } +} + + /*These tests, test for availability of include file in the malloc'd buffer **The malloc'd buffer, only contains files to be included */ @@ -1150,6 +1177,7 @@ void register_kvp_functions( void ) UT_add_test(gpKVPSuite2, "kvp double", test_ut_kvp_getDoubleField); UT_add_test(gpKVPSuite2, "kvp node presence", test_ut_kvp_fieldPresent); UT_add_test(gpKVPSuite2, "kvp dataByte", test_ut_kvp_dataByte); + UT_add_test(gpKVPSuite2, "kvp get JSON data", test_ut_kvp_getDataOfTypeJson); /* Perform the same parsing tests but use a json file instead */ gpKVPSuite3 = UT_add_suite("ut-kvp - test main functions JSON Decoder ", test_ut_kvp_createGlobalJSONInstance, test_ut_kvp_freeGlobalInstance); @@ -1166,6 +1194,7 @@ void register_kvp_functions( void ) UT_add_test(gpKVPSuite3, "kvp float", test_ut_kvp_getFloatField); UT_add_test(gpKVPSuite3, "kvp double", test_ut_kvp_getDoubleField); UT_add_test(gpKVPSuite3, "kvp node presence", test_ut_kvp_fieldPresent); + UT_add_test(gpKVPSuite3, "kvp get Yaml data", test_ut_kvp_getDataOfTypeYaml); gpKVPSuite4 = UT_add_suite("ut-kvp - test main functions Test without Open ", NULL, NULL); diff --git a/tests/websocket-clients/curl-get-client-json-incorrect.sh b/tests/websocket-clients/curl-get-client-json-incorrect.sh new file mode 100755 index 0000000..6728978 --- /dev/null +++ b/tests/websocket-clients/curl-get-client-json-incorrect.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/getKVP?key=test" -H "Accept: application/json" diff --git a/tests/websocket-clients/curl-get-client-json.sh b/tests/websocket-clients/curl-get-client-json.sh new file mode 100755 index 0000000..58a41c9 --- /dev/null +++ b/tests/websocket-clients/curl-get-client-json.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/getKVP?key=test/jsonData" -H "Accept: application/json" diff --git a/tests/websocket-clients/curl-get-client-no-header.sh b/tests/websocket-clients/curl-get-client-no-header.sh new file mode 100755 index 0000000..9c6d0de --- /dev/null +++ b/tests/websocket-clients/curl-get-client-no-header.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/getKVP?key=test/yamlData" diff --git a/tests/websocket-clients/curl-get-client-yaml-incorrect.sh b/tests/websocket-clients/curl-get-client-yaml-incorrect.sh new file mode 100755 index 0000000..4cb369a --- /dev/null +++ b/tests/websocket-clients/curl-get-client-yaml-incorrect.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/getKVP?key=test" -H "Accept: application/x-yaml" diff --git a/tests/websocket-clients/curl-get-client-yaml.sh b/tests/websocket-clients/curl-get-client-yaml.sh new file mode 100755 index 0000000..3c2bffa --- /dev/null +++ b/tests/websocket-clients/curl-get-client-yaml.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/getKVP?key=test/yamlData" -H "Accept: application/x-yaml" diff --git a/tests/websocket-clients/curl-client-binary.sh b/tests/websocket-clients/curl-push-client-binary.sh similarity index 100% rename from tests/websocket-clients/curl-client-binary.sh rename to tests/websocket-clients/curl-push-client-binary.sh diff --git a/tests/websocket-clients/curl-client-json.sh b/tests/websocket-clients/curl-push-client-json.sh similarity index 100% rename from tests/websocket-clients/curl-client-json.sh rename to tests/websocket-clients/curl-push-client-json.sh diff --git a/tests/websocket-clients/curl-client-yaml.sh b/tests/websocket-clients/curl-push-client-yaml.sh similarity index 100% rename from tests/websocket-clients/curl-client-yaml.sh rename to tests/websocket-clients/curl-push-client-yaml.sh diff --git a/tests/websocket-clients/test_script_for_curl_request.sh b/tests/websocket-clients/test_script_for_curl_request.sh new file mode 100755 index 0000000..316bf22 --- /dev/null +++ b/tests/websocket-clients/test_script_for_curl_request.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Define color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No color + +# Define test scripts and expected results +declare -A tests=( + ["./curl-get-client-yaml-incorrect.sh"]="error: Internal Server Error" + ["./curl-get-client-yaml.sh"]="--- +test: + yamlData: somevalue + x: 1 + on: true +test2: + yamlData1: somevalue1 + y: 2 + off: false" + ["./curl-get-client-json-incorrect.sh"]='{"error": "Internal Server Error"}' + ["./curl-get-client-json.sh"]='{ + "test": { + "jsonData": "somevalue", + "x": 1, + "on": true + }, + "test2": { + "jsonData1": "somevalue1", + "y": 2, + "off": false + } +}' + ["./curl-get-client-no-header.sh"]='{"error": "Unsupported Accept header or invalid type"}' + ["./curl-push-client-binary.sh"]="" + ["./curl-push-client-json.sh"]="" + ["./curl-push-client-yaml.sh"]="" +) + +# Loop through tests and validate output +for script in "${!tests[@]}"; do + echo "Running: $script" + output=$($script) + expected="${tests[$script]}" + + if [[ "$output" == "$expected" ]]; then + echo -e "${GREEN}Test Passed: Output matches expected result.${NC}" + else + echo -e "${RED}Test Failed: Output does not match expected result.${NC}" + echo -e "${YELLOW}Expected:${NC}" + echo "$expected" + echo "${YELLOW}Got:${NC}" + echo "$output" + fi + echo "---------------------------------" +done From 6bd937b9bf9a4ee5b8f578f14228671b4555f348 Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Tue, 28 Jan 2025 16:08:04 +0000 Subject: [PATCH 3/9] Fix gh66 : Fix review comments --- include/ut_control_plane.h | 44 +++ src/ut_control_plane.c | 358 +++++++++++------- tests/src/ut_test_control_plane.c | 43 ++- .../curl-get-client-json-incorrect.sh | 2 +- .../websocket-clients/curl-get-client-json.sh | 2 +- .../curl-get-client-no-header.sh | 2 +- .../curl-get-client-yaml-incorrect.sh | 2 +- .../websocket-clients/curl-get-client-yaml.sh | 2 +- .../curl-push-client-binary.sh | 4 +- .../curl-push-client-json.sh | 2 +- .../curl-push-client-yaml.sh | 2 +- tests/websocket-clients/get_example.json | 21 + tests/websocket-clients/get_example.yaml | 14 + .../test_script_for_curl_request.sh | 65 ++-- 14 files changed, 385 insertions(+), 178 deletions(-) create mode 100644 tests/websocket-clients/get_example.json create mode 100644 tests/websocket-clients/get_example.yaml diff --git a/include/ut_control_plane.h b/include/ut_control_plane.h index bdb5804..b6910e5 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -48,8 +48,34 @@ typedef struct typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ /** @brief Callback function type for handling control plane messages. */ +/** + * @typedef ut_control_callback_t + * @brief A callback function type for handling control operations. + * + * This callback function is called with a key, an instance of ut_kvp_instance_t, + * and user-defined data. + * + * @param key The key associated with the control operation. + * @param instance A pointer to a ut_kvp_instance_t instance. + * @param userData A pointer to user-defined data. + */ typedef void (*ut_control_callback_t)( char *key, ut_kvp_instance_t *instance, void *userData ); +/** + * @typedef ut_control_string_callback_t + * @brief A callback function type for handling control operations with formatted strings. + * + * This callback function is called with a key, an instance of ut_kvp_instance_t, + * user-defined data, and a format string. It returns a formatted string. + * + * @param key The key associated with the control operation. + * @param instance A pointer to a ut_kvp_instance_t instance. + * @param userData A pointer to user-defined data. + * @param format A constant character pointer representing the format string. + * @return A formatted string. + */ +typedef char* (*ut_control_string_callback_t)( char *key, ut_kvp_instance_t *instance, void *userData, const char* format ); + /** * @brief Initializes a control plane instance. * @param monitorPort - Port number to monitor for incoming messages. @@ -74,6 +100,24 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl ut_control_callback_t callbackFunction, void *userData); +/** + * @brief Registers a string callback function for a specific message key in the control plane instance. + * + * This function allows the user to register a callback function that will be invoked when a message + * with the specified key is received by the control plane instance. + * + * @param pInstance Pointer to the control plane instance. + * @param key The key associated with the message for which the callback is to be registered. + * @param callbackFunction The callback function to be invoked when the message with the specified key is received. + * @param userData User-defined data to be passed to the callback function. + * + * @return Status of the registration operation. + */ +ut_control_plane_status_t UT_ControlPlane_RegisterStringCallbackOnMessage(ut_controlPlane_instance_t *pInstance, + char *key, + ut_control_string_callback_t callbackFunction, + void *userData); + /** * @brief Starts the control plane listening for incoming messages. * @param pInstance - Handle to the control plane instance. diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index 38ab7ed..03839ef 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -41,6 +41,7 @@ typedef struct { char key[UT_KVP_MAX_ELEMENT_SIZE]; ut_control_callback_t pCallback; + ut_control_string_callback_t pStringCallback; void* userData; }CallbackEntry_t; @@ -289,39 +290,45 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void } #else +// Function to compare strings with handling of leading '/' +static int compareStrings(const char *str1, const char *str2) +{ + // If str2 starts with '/', skip it for comparison + if (str2[0] == '/') + { + str2++; // Move pointer to skip the '/' + } + + if (str1[0] == '/') + { + str1++; // Move pointer to skip the '/' + } + return strcmp(str1, str2); // Compare adjusted strings +} + static char* create_response(ut_cp_instance_internal_t *pInternal, const char* key, const char* type) { ut_kvp_instance_t *pkvpInstance = NULL; ut_kvp_status_t status; - char result_kvp[UT_KVP_MAX_ELEMENT_SIZE] = {0xff}; char* response = NULL; for (uint32_t i = 0; i < pInternal->callback_entry_index; i++) { CallbackEntry_t entry = pInternal->callbackEntryList[i]; - void *userData = malloc(strlen(entry.userData) + 1); // +1 for null terminator - if (userData == NULL) - { - UT_CONTROL_PLANE_ERROR("Memory allocation failed\n"); - return NULL; // Handle memory allocation failure - } - memcpy(userData, entry.userData, strlen(entry.userData) + 1); - pkvpInstance = ut_kvp_createInstance(); - - /* Note: userData data will be freed by the destoryInstance() function */ - status = ut_kvp_openMemory(pkvpInstance, userData, strlen(entry.userData)); - if (status != UT_KVP_STATUS_SUCCESS) + if (compareStrings(entry.key, key) == 0) { - UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n"); + pkvpInstance = ut_kvp_createInstance(); + status = ut_kvp_openMemory(pkvpInstance, entry.userData, strlen(entry.userData)); + if (status != UT_KVP_STATUS_SUCCESS) + { + UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n"); + ut_kvp_destroyInstance(pkvpInstance); + return NULL; + } + response = entry.pStringCallback((char*)key, pkvpInstance, entry.userData, type); ut_kvp_destroyInstance(pkvpInstance); - return NULL; - } - if (UT_KVP_STATUS_SUCCESS == ut_kvp_getStringField(pkvpInstance, key, result_kvp, UT_KVP_MAX_ELEMENT_SIZE)) - { - response = ut_kvp_getDataOfType(pkvpInstance, type); } - ut_kvp_destroyInstance(pkvpInstance); } return response; @@ -366,45 +373,31 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI - char query_string[256] = {0}; // Buffer for the query string char accept_header[256] = {0}; // Buffer for the Accept header - char *response = NULL; - char *key = NULL; unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body - unsigned char *p = buffer + LWS_PRE; // Pointer to start of usable buffer space - unsigned char *end = buffer + sizeof(buffer); // Pointer to end of buffer UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri); + // Handle POST request for /api/postRequest + if (strcmp(requested_uri, "/api/postRequest") == 0) + { + lws_callback_on_writable(wsi); + return 0; // Let the body handling process continue + } + // Handle GET request for /api/getKVP - if (strcmp(requested_uri, "/api/getKVP") == 0) + if (strncmp(requested_uri, "/api/", 5) == 0) { - // Extract the query string (if any) - if (lws_hdr_copy(wsi, query_string, sizeof(query_string), WSI_TOKEN_HTTP_URI_ARGS) > 0) - { - UT_CONTROL_PLANE_DEBUG("Query String: %s\n", query_string); + // Extract the key from the URI (part after "/api/") + char *key_start = requested_uri + 5; // Skip "/api/" + char key[256] = {0}; + strncpy(key, key_start, sizeof(key) - 1); - // Directly look for the "key=" prefix in the query string - char *key_param = strstr(query_string, "key="); - if (key_param != NULL) - { - key = key_param + 4; // Extract the value part (skip "key=") - UT_CONTROL_PLANE_DEBUG("Parsed Query Parameter: key=%s\n", key); - } - else - { - UT_CONTROL_PLANE_ERROR("Query parameter 'key' not found\n"); - key = NULL; // Ensure key is NULL if not found - } - } - else - { - UT_CONTROL_PLANE_ERROR("Failed to extract query string\n"); - key = NULL; // Ensure key is NULL if query string is absent - } + UT_CONTROL_PLANE_DEBUG("Extracted Key: %s\n", key); // Extract the Accept header + char accept_header[128] = {0}; if (lws_hdr_copy(wsi, accept_header, sizeof(accept_header), WSI_TOKEN_HTTP_ACCEPT) > 0) { UT_CONTROL_PLANE_DEBUG("Accept Header: %s\n", accept_header); @@ -412,118 +405,152 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void else { UT_CONTROL_PLANE_ERROR("Missing Accept header\n"); - const char *error_response = "{\"error\": \"Missing Accept header\"}"; - if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0) + + const char *error_response_json = "{\"error\": \"Missing Accept header\"}"; + const char *error_response_yaml = "error: Missing Accept header\n"; + + // Default to JSON if Accept header is missing + const char *response_format = "application/json"; + const char *error_response = error_response_json; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response_format = "application/x-yaml"; + error_response = error_response_yaml; + } + + if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) return -1; return -1; } - // Check for valid key parameter - if (key) + // Check if key is valid + if (strlen(key) == 0) { - if (strncmp(accept_header, "application/json", 16) == 0) + UT_CONTROL_PLANE_ERROR("Missing key in the URI\n"); + + const char *error_response_json = "{\"error\": \"Missing key in URI\"}"; + const char *error_response_yaml = "error: Missing key in URI\n"; + + const char *response_format = "application/json"; + const char *error_response = error_response_json; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) { - response = create_response(pInternal, key, "json"); - - if (response == NULL) - { - UT_CONTROL_PLANE_ERROR("Failed to create response\n"); - const char *error_response = "{\"error\": \"Internal Server Error\"}"; - if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/json", error_response) < 0) - return -1; - return -1; - } - - // Add HTTP headers - if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) - { - return -1; // Failed to add headers - } - - // Finalize headers - if (lws_finalize_http_header(wsi, &p, end) < 0) - { - return -1; // Failed to finalize headers - } - - // Write headers - if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) - { - return -1; // Failed to write headers - } - - // Write body - if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) - { - return -1; // Failed to write body - } - - free(response); - - return 1; // HTTP request handled + response_format = "application/x-yaml"; + error_response = error_response_yaml; } - else if (strncmp(accept_header, "application/x-yaml", 18) == 0) + + if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) + return -1; + return -1; + } + + // Generate response based on Accept header + char *response = NULL; + if (strncmp(accept_header, "application/json", 16) == 0) + { + response = create_response(pInternal, key, "json"); + } + else if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response = create_response(pInternal, key, "yaml"); + } + else + { + UT_CONTROL_PLANE_ERROR("Unsupported Accept header\n"); + + const char *error_response_json = "{\"error\": \"Unsupported Accept header\"}"; + const char *error_response_yaml = "error: Unsupported Accept header\n"; + + const char *response_format = "application/json"; + const char *error_response = error_response_json; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) { - response = create_response(pInternal, key, "yaml"); - - if (response == NULL) - { - UT_CONTROL_PLANE_ERROR("Failed to create response\n"); - const char *error_response = "error: Internal Server Error\n"; - if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, "application/x-yaml", error_response) < 0) - return -1; - return -1; - } - - // Add HTTP headers - if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, "application/json", strlen(response), &p, end) < 0) - { - return -1; // Failed to add headers - } - - // Finalize headers - if (lws_finalize_http_header(wsi, &p, end) < 0) - { - return -1; // Failed to finalize headers - } - - // Write headers - if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) - { - return -1; // Failed to write headers - } - - // Write body - if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) - { - return -1; // Failed to write body - } - - free(response); - - return 1; // HTTP request handled + response_format = "application/x-yaml"; + error_response = error_response_yaml; } - else - { - UT_CONTROL_PLANE_ERROR("Invalid key value or unsupported Accept header\n"); - const char *error_response = "{\"error\": \"Unsupported Accept header or invalid type\"}"; - if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, "application/json", error_response) < 0) - return -1; + + if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) return -1; - } + return -1; } - else + + // Check if response generation succeeded + if (response == NULL) { - UT_CONTROL_PLANE_ERROR("Missing or invalid key parameter\n"); - lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); + UT_CONTROL_PLANE_ERROR("Failed to create response\n"); + + const char *error_response_json = "{\"error\": \"Internal Server Error\"}"; + const char *error_response_yaml = "error: Internal Server Error\n"; + + const char *response_format = "application/json"; + const char *error_response = error_response_json; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response_format = "application/x-yaml"; + error_response = error_response_yaml; + } + + if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, response_format, error_response) < 0) + return -1; return -1; } + + // Add HTTP headers + unsigned char *p = buffer + LWS_PRE, *end = buffer + sizeof(buffer) - 1; + if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, accept_header, strlen(response), &p, end) < 0) + { + free(response); + return -1; // Failed to add headers + } + + // Finalize headers + if (lws_finalize_http_header(wsi, &p, end) < 0) + { + free(response); + return -1; // Failed to finalize headers + } + + // Write headers + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { + free(response); + return -1; // Failed to write headers + } + + // Write body + if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) + { + free(response); + return -1; // Failed to write body + } + + free(response); + + return 1; // HTTP request handled successfully } - // Handle POST request for /api/postKVP - if (strcmp(requested_uri, "/api/postKVP") == 0) + else { - lws_callback_on_writable(wsi); - return 0; // Let the body handling process continue + UT_CONTROL_PLANE_ERROR("Invalid URI: %s\n", requested_uri); + + const char *error_response_json = "{\"error\": \"Invalid URI\"}"; + const char *error_response_yaml = "error: Invalid URI\n"; + + const char *response_format = "application/json"; + const char *error_response = error_response_json; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response_format = "application/x-yaml"; + error_response = error_response_yaml; + } + + if (send_error_response(wsi, HTTP_STATUS_NOT_FOUND, response_format, error_response) < 0) + return -1; + return -1; } break; @@ -746,6 +773,49 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, key,UT_KVP_MAX_ELEMENT_SIZE); pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = callbackFunction; pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; + pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = NULL; + pInternal->callback_entry_index++; + UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); + return UT_CONTROL_PLANE_STATUS_OK; +} + +ut_control_plane_status_t UT_ControlPlane_RegisterStringCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_string_callback_t callbackFunction, void *userData) +{ + ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; + + if ( pInternal == NULL ) + { + UT_CONTROL_PLANE_ERROR("Invalid Handle\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_HANDLE; + } + + if ( key == NULL ) + { + UT_CONTROL_PLANE_ERROR("Invalid Param\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } + + if ( callbackFunction == NULL ) + { + UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } + + if ( userData == NULL ) + { + UT_CONTROL_PLANE_ERROR("NULL userData\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } + + + if ( pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES ) + { + return UT_CONTROL_PLANE_STATUS_LIST_FULL; + } + strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, key,UT_KVP_MAX_ELEMENT_SIZE); + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = NULL; + pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; + pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = callbackFunction; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index f1607c8..739a67e 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -35,6 +35,8 @@ #define UT_CONTROL_YAML_FILE "example.yaml" #define UT_CONTROL_JSON_FILE "example.json" +#define UT_CONTROL_GET_FILE_JSON "get_example.json" +#define UT_CONTROL_GET_FILE_YAML "get_example.yaml" static UT_test_suite_t *gpAssertSuite1 = NULL; static UT_test_suite_t *gpAssertSuite2 = NULL; @@ -43,7 +45,7 @@ static UT_test_suite_t *gpAssertSuite3 = NULL; static ut_controlPlane_instance_t *gInstance = NULL; static volatile bool gMessageRecievedYAML = false; static volatile bool gMessageRecievedJSON = false; -static test_ut_memory_t gUserDataYaml, gUserDataJson; +static test_ut_memory_t gUserDataYaml, gUserDataJson, gUserDataGetJson, gUserDataGetYaml; const static ut_control_keyStringMapping_t numericMaptable [] = { { "one", (int32_t)1 }, @@ -52,6 +54,8 @@ const static ut_control_keyStringMapping_t numericMaptable [] = { }; void testYAMLCallback(char *key, ut_kvp_instance_t *instance, void* userData); +char* testGETCallback(char *key, ut_kvp_instance_t *instance, void* userData, const char* format); + /* L1 Function tests */ static void test_ut_control_l1_testInitExit() @@ -217,6 +221,19 @@ void testJSONCallback(char *key, ut_kvp_instance_t *instance, void* userData) gMessageRecievedJSON = true; } +char* testGETCallback(char *key, ut_kvp_instance_t *instance, void* userData, const char* format) +{ + char *kvpData; + printf("*******************************Inside testGETCallback************************\n"); + kvpData = ut_kvp_getDataOfType(instance, format); + + if (kvpData == NULL) + { + return NULL; + } + return kvpData; +} + static void UT_ControlPlane_Sigint_Handler(int sig) { UT_LOG("Signal Handler invoked\n"); @@ -264,6 +281,28 @@ static void test_ut_control_performStart() } gMessageRecievedJSON = false; + + if (read_file_into_memory(UT_CONTROL_GET_FILE_YAML, &gUserDataGetYaml) == 0) + { + if (gUserDataGetYaml.buffer != NULL) + { + printf("Original Yaml file\n%s", (char*)gUserDataGetYaml.buffer); + } + + UT_LOG("UT_ControlPlane_RegisterStringCallbackOnMessage() client testGETCallback - Positive \n"); + UT_ControlPlane_RegisterStringCallbackOnMessage(gInstance, "/v1/callMyFunction", &testGETCallback, (void *)gUserDataGetYaml.buffer); + } + + if (read_file_into_memory(UT_CONTROL_GET_FILE_JSON, &gUserDataGetJson) == 0) + { + if (gUserDataGetJson.buffer != NULL) + { + printf("Original Json file\n%s", (char*)gUserDataGetJson.buffer); + } + + UT_LOG("UT_ControlPlane_RegisterStringCallbackOnMessage() client testGETCallback - Positive \n"); + UT_ControlPlane_RegisterStringCallbackOnMessage(gInstance, "/v1/callMyFunction2", &testGETCallback, (void *)gUserDataGetJson.buffer); + } } void run_client_function() @@ -276,7 +315,7 @@ void run_client_function() UT_LOG("Please Run the command `./python-client-send-json.py or/& ./python-client-send-yaml.py` from another terminal and press return;'\n"); UT_LOG("In order to pass the test you need to run each of the python scripts'\n"); #else - UT_LOG("Please Run the command `./curl-requests-script.sh` or `test_script_for_curl_request.sh` from another terminal and press return;'\n"); + UT_LOG("Please Run the command `test_script_for_curl_request.sh` from another terminal and press return;'\n"); UT_LOG("In order to pass the test you need to run each of the curl scripts'\n"); #endif diff --git a/tests/websocket-clients/curl-get-client-json-incorrect.sh b/tests/websocket-clients/curl-get-client-json-incorrect.sh index 6728978..a6448b0 100755 --- a/tests/websocket-clients/curl-get-client-json-incorrect.sh +++ b/tests/websocket-clients/curl-get-client-json-incorrect.sh @@ -1 +1 @@ -curl -X GET "http://localhost:8080/api/getKVP?key=test" -H "Accept: application/json" +curl -X GET "http://localhost:8080/api/v1/callMyIncorrectFunction" -H "Accept: application/json" diff --git a/tests/websocket-clients/curl-get-client-json.sh b/tests/websocket-clients/curl-get-client-json.sh index 58a41c9..d016b91 100755 --- a/tests/websocket-clients/curl-get-client-json.sh +++ b/tests/websocket-clients/curl-get-client-json.sh @@ -1 +1 @@ -curl -X GET "http://localhost:8080/api/getKVP?key=test/jsonData" -H "Accept: application/json" +curl -X GET "http://localhost:8080/api/v1/callMyFunction2" -H "Accept: application/json" diff --git a/tests/websocket-clients/curl-get-client-no-header.sh b/tests/websocket-clients/curl-get-client-no-header.sh index 9c6d0de..dd40113 100755 --- a/tests/websocket-clients/curl-get-client-no-header.sh +++ b/tests/websocket-clients/curl-get-client-no-header.sh @@ -1 +1 @@ -curl -X GET "http://localhost:8080/api/getKVP?key=test/yamlData" +curl -X GET "http://localhost:8080/api/v1/callNoHeaderMyFunction" diff --git a/tests/websocket-clients/curl-get-client-yaml-incorrect.sh b/tests/websocket-clients/curl-get-client-yaml-incorrect.sh index 4cb369a..136135f 100755 --- a/tests/websocket-clients/curl-get-client-yaml-incorrect.sh +++ b/tests/websocket-clients/curl-get-client-yaml-incorrect.sh @@ -1 +1 @@ -curl -X GET "http://localhost:8080/api/getKVP?key=test" -H "Accept: application/x-yaml" +curl -X GET "http://localhost:8080/api/v1/callIncorrectYaml" -H "Accept: application/x-yaml" diff --git a/tests/websocket-clients/curl-get-client-yaml.sh b/tests/websocket-clients/curl-get-client-yaml.sh index 3c2bffa..c121f83 100755 --- a/tests/websocket-clients/curl-get-client-yaml.sh +++ b/tests/websocket-clients/curl-get-client-yaml.sh @@ -1 +1 @@ -curl -X GET "http://localhost:8080/api/getKVP?key=test/yamlData" -H "Accept: application/x-yaml" +curl -X GET "http://localhost:8080/api/v1/callMyFunction" -H "Accept: application/x-yaml" diff --git a/tests/websocket-clients/curl-push-client-binary.sh b/tests/websocket-clients/curl-push-client-binary.sh index a380117..2c6f2db 100755 --- a/tests/websocket-clients/curl-push-client-binary.sh +++ b/tests/websocket-clients/curl-push-client-binary.sh @@ -1,2 +1,2 @@ -curl -X POST http://localhost:8080/api/postKVP -H "Content-Type: application/octet-stream" --data-binary "@example.yaml" -curl -X POST http://localhost:8080/api/postKVP -H "Content-Type: application/octet-stream" --data-binary "@example.json" \ No newline at end of file +curl -X POST http://localhost:8080/api/postRequest -H "Content-Type: application/octet-stream" --data-binary "@example.yaml" +curl -X POST http://localhost:8080/api/postRequest -H "Content-Type: application/octet-stream" --data-binary "@example.json" \ No newline at end of file diff --git a/tests/websocket-clients/curl-push-client-json.sh b/tests/websocket-clients/curl-push-client-json.sh index d7ff4a2..700cc53 100755 --- a/tests/websocket-clients/curl-push-client-json.sh +++ b/tests/websocket-clients/curl-push-client-json.sh @@ -1 +1 @@ -curl -X POST -H "Content-Type: application/json" --data "@example.json" http://localhost:8080/api/postKVP \ No newline at end of file +curl -X POST -H "Content-Type: application/json" --data "@example.json" http://localhost:8080/api/postRequest \ No newline at end of file diff --git a/tests/websocket-clients/curl-push-client-yaml.sh b/tests/websocket-clients/curl-push-client-yaml.sh index b93570d..d565f22 100755 --- a/tests/websocket-clients/curl-push-client-yaml.sh +++ b/tests/websocket-clients/curl-push-client-yaml.sh @@ -1 +1 @@ -curl -X POST -H "Content-Type: application/x-yaml" --data-binary "@example.yaml" http://localhost:8080/api/postKVP +curl -X POST -H "Content-Type: application/x-yaml" --data-binary "@example.yaml" http://localhost:8080/api/postRequest diff --git a/tests/websocket-clients/get_example.json b/tests/websocket-clients/get_example.json new file mode 100644 index 0000000..5e76e8f --- /dev/null +++ b/tests/websocket-clients/get_example.json @@ -0,0 +1,21 @@ +{ + "name": "John Doe", + "age": 30, + "email": "johndoe@example.com", + "isMarried": false, + "children": [ + { + "name": "Alice", + "age": 5 + }, + { + "name": "Bob", + "age": 3 + } + ], + "hobbies": [ + "reading", + "cycling", + "traveling" + ] +} diff --git a/tests/websocket-clients/get_example.yaml b/tests/websocket-clients/get_example.yaml new file mode 100644 index 0000000..5c92927 --- /dev/null +++ b/tests/websocket-clients/get_example.yaml @@ -0,0 +1,14 @@ +--- +name: John Doe +age: 30 +email: johndoe@example.com +isMarried: false +children: +- name: Alice + age: 5 +- name: Bob + age: 3 +hobbies: +- reading +- cycling +- traveling diff --git a/tests/websocket-clients/test_script_for_curl_request.sh b/tests/websocket-clients/test_script_for_curl_request.sh index 316bf22..07d88ef 100755 --- a/tests/websocket-clients/test_script_for_curl_request.sh +++ b/tests/websocket-clients/test_script_for_curl_request.sh @@ -4,35 +4,48 @@ RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' -BLUE='\033[0;34m' NC='\033[0m' # No color # Define test scripts and expected results declare -A tests=( ["./curl-get-client-yaml-incorrect.sh"]="error: Internal Server Error" ["./curl-get-client-yaml.sh"]="--- -test: - yamlData: somevalue - x: 1 - on: true -test2: - yamlData1: somevalue1 - y: 2 - off: false" +name: John Doe +age: 30 +email: johndoe@example.com +isMarried: false +children: +- name: Alice + age: 5 +- name: Bob + age: 3 +hobbies: +- reading +- cycling +- traveling" ["./curl-get-client-json-incorrect.sh"]='{"error": "Internal Server Error"}' ["./curl-get-client-json.sh"]='{ - "test": { - "jsonData": "somevalue", - "x": 1, - "on": true - }, - "test2": { - "jsonData1": "somevalue1", - "y": 2, - "off": false - } + "name": "John Doe", + "age": 30, + "email": "johndoe@example.com", + "isMarried": false, + "children": [ + { + "name": "Alice", + "age": 5 + }, + { + "name": "Bob", + "age": 3 + } + ], + "hobbies": [ + "reading", + "cycling", + "traveling" + ] }' - ["./curl-get-client-no-header.sh"]='{"error": "Unsupported Accept header or invalid type"}' + ["./curl-get-client-no-header.sh"]='{"error": "Unsupported Accept header"}' ["./curl-push-client-binary.sh"]="" ["./curl-push-client-json.sh"]="" ["./curl-push-client-yaml.sh"]="" @@ -41,16 +54,22 @@ test2: # Loop through tests and validate output for script in "${!tests[@]}"; do echo "Running: $script" - output=$($script) - expected="${tests[$script]}" + # Capture script output, removing leading/trailing whitespace + output=$($script | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + # Remove any color codes from output (if present) + output=$(echo "$output" | sed -r 's/\x1B(\[[0-9;]*[JKmsu]|\(B)//g') + # Get the expected result, also trimming any whitespace + expected=$(echo "${tests[$script]}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + + # Compare outputs if [[ "$output" == "$expected" ]]; then echo -e "${GREEN}Test Passed: Output matches expected result.${NC}" else echo -e "${RED}Test Failed: Output does not match expected result.${NC}" echo -e "${YELLOW}Expected:${NC}" echo "$expected" - echo "${YELLOW}Got:${NC}" + echo -e "${YELLOW}Got:${NC}" echo "$output" fi echo "---------------------------------" From a846b89991130fa2c28455027790f24c89be7b77 Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:22:18 +0000 Subject: [PATCH 4/9] Fix gh# 66 : Fixing further review comments --- include/ut_control_plane.h | 59 ++-- src/ut_control_plane.c | 300 ++++++++---------- tests/src/ut_test_control_plane.c | 41 +-- .../test_script_for_curl_request.sh | 2 +- 4 files changed, 177 insertions(+), 225 deletions(-) diff --git a/include/ut_control_plane.h b/include/ut_control_plane.h index b6910e5..a787dea 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -47,34 +47,31 @@ typedef struct typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ -/** @brief Callback function type for handling control plane messages. */ /** - * @typedef ut_control_callback_t - * @brief A callback function type for handling control operations. + * @brief Callback function type for handling control plane POST triggers. * - * This callback function is called with a key, an instance of ut_kvp_instance_t, - * and user-defined data. + * This callback function is invoked when a POST request is received + * at a registered endpoint and the triggerKey is matched on the incoming data. * - * @param key The key associated with the control operation. - * @param instance A pointer to a ut_kvp_instance_t instance. - * @param userData A pointer to user-defined data. + * @param triggerKey The trigger key that was matched. + * @param instance The key-value pair instance containing the incoming data. + * @param userData User-defined data passed to the callback function. */ -typedef void (*ut_control_callback_t)( char *key, ut_kvp_instance_t *instance, void *userData ); +typedef void (*ut_control_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); /** - * @typedef ut_control_string_callback_t - * @brief A callback function type for handling control operations with formatted strings. + * @brief Callback function type for handling control plane GET API calls. * - * This callback function is called with a key, an instance of ut_kvp_instance_t, - * user-defined data, and a format string. It returns a formatted string. + * This callback function is invoked when a GET request is received + * at a registered endpoint. It allows the user to implement the + * REST API call. * - * @param key The key associated with the control operation. - * @param instance A pointer to a ut_kvp_instance_t instance. - * @param userData A pointer to user-defined data. - * @param format A constant character pointer representing the format string. - * @return A formatted string. + * @param restAPI The name of the REST API being called. + * @param userData User-defined data passed to the callback function. + * + * @returns A character string containing the result of the API call, in JSON or YAML format */ -typedef char* (*ut_control_string_callback_t)( char *key, ut_kvp_instance_t *instance, void *userData, const char* format ); +typedef char *(*ut_control_REST_API_callback_t)(char *restAPI, void *userData); /** * @brief Initializes a control plane instance. @@ -101,22 +98,24 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl void *userData); /** - * @brief Registers a string callback function for a specific message key in the control plane instance. + * @brief Registers a callback function to handle requests for a specific REST API GET endpoint. * - * This function allows the user to register a callback function that will be invoked when a message - * with the specified key is received by the control plane instance. + * This function registers a callback function that will be invoked when a request + * is received for the specified REST API endpoint. The callback function will be + * responsible for parsing the request, processing it, and generating a response. * - * @param pInstance Pointer to the control plane instance. - * @param key The key associated with the message for which the callback is to be registered. - * @param callbackFunction The callback function to be invoked when the message with the specified key is received. + * @param pInstance A pointer to the control plane instance. + * @param restAPI The name of the REST API GET endpoint. + * @param callbackFunction The callback function to be invoked. * @param userData User-defined data to be passed to the callback function. * - * @return Status of the registration operation. + * @returns A status code indicating the success or failure of the registration. */ -ut_control_plane_status_t UT_ControlPlane_RegisterStringCallbackOnMessage(ut_controlPlane_instance_t *pInstance, - char *key, - ut_control_string_callback_t callbackFunction, - void *userData); +ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( + ut_controlPlane_instance_t *pInstance, + char *restAPI, + ut_control_REST_API_callback_t callbackFunction, + void *userData); /** * @brief Starts the control plane listening for incoming messages. diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index 03839ef..4573e28 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -41,7 +41,7 @@ typedef struct { char key[UT_KVP_MAX_ELEMENT_SIZE]; ut_control_callback_t pCallback; - ut_control_string_callback_t pStringCallback; + ut_control_REST_API_callback_t pStringCallback; void* userData; }CallbackEntry_t; @@ -308,9 +308,10 @@ static int compareStrings(const char *str1, const char *str2) static char* create_response(ut_cp_instance_internal_t *pInternal, const char* key, const char* type) { + char* response = NULL; + char* kvpData = NULL; ut_kvp_instance_t *pkvpInstance = NULL; ut_kvp_status_t status; - char* response = NULL; for (uint32_t i = 0; i < pInternal->callback_entry_index; i++) { @@ -318,15 +319,17 @@ static char* create_response(ut_cp_instance_internal_t *pInternal, const char* k if (compareStrings(entry.key, key) == 0) { + kvpData = entry.pStringCallback((char *)key, entry.userData); + pkvpInstance = ut_kvp_createInstance(); - status = ut_kvp_openMemory(pkvpInstance, entry.userData, strlen(entry.userData)); + status = ut_kvp_openMemory(pkvpInstance, kvpData, strlen(kvpData)); if (status != UT_KVP_STATUS_SUCCESS) { - UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n"); + UT_CONTROL_PLANE_ERROR("ut_kvp_openMemory() - Read Failure\n"); ut_kvp_destroyInstance(pkvpInstance); return NULL; } - response = entry.pStringCallback((char*)key, pkvpInstance, entry.userData, type); + response = ut_kvp_getDataOfType(pkvpInstance, type); ut_kvp_destroyInstance(pkvpInstance); } } @@ -359,6 +362,67 @@ static int send_error_response(struct lws *wsi, int status, const char *content_ return 0; } +// Function to send error response +static int send_error(void *wsi, int status, const char *accept_header, const char *json_msg, const char *yaml_msg) +{ + const char *response_format = "application/json"; + const char *error_response = json_msg; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response_format = "application/x-yaml"; + error_response = yaml_msg; + } + + return send_error_response(wsi, status, response_format, error_response) < 0 ? -1 : -1; +} + +// Function to validate Accept header +static int validate_accept_header(void *wsi, char *accept_header, size_t size) +{ + if (lws_hdr_copy(wsi, accept_header, size, WSI_TOKEN_HTTP_ACCEPT) <= 0 || + strncmp(accept_header, "application", 11) != 0) + { + UT_CONTROL_PLANE_ERROR("Missing or Invalid Accept header\n"); + return send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Missing or Invalid Accept header\"}", + "error: Missing or Invalid Accept header\n"); + } + return 0; // Success +} + +// Function to extract key from URI +static int extract_key(const char *requested_uri, char *key, size_t size) +{ + char *key_start = (char* )requested_uri + 5; // Skip "/api/" + if (strlen(key_start) == 0) + { + UT_CONTROL_PLANE_ERROR("Missing key in the URI\n"); + return -1; + } + strncpy(key, key_start, size - 1); + UT_CONTROL_PLANE_DEBUG("Extracted Key: %s\n", key); + return 0; // Success +} + +// Function to determine response format +static char *determine_response_format(void *pInternal, const char *key, const char *accept_header) +{ + if (strncmp(accept_header, "application/json", 16) == 0) + { + return create_response(pInternal, key, "json"); + } + else if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + return create_response(pInternal, key, "yaml"); + } + else + { + UT_CONTROL_PLANE_ERROR("Internal Server Error\n"); + return NULL; + } +} + static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { cp_message_t msg; @@ -372,11 +436,10 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); - char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI - char accept_header[256] = {0}; // Buffer for the Accept header + char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI + char accept_header[128] = {0}; // Buffer for the Accept header unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body - UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri); // Handle POST request for /api/postRequest @@ -386,173 +449,70 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void return 0; // Let the body handling process continue } - // Handle GET request for /api/getKVP - if (strncmp(requested_uri, "/api/", 5) == 0) - { - // Extract the key from the URI (part after "/api/") - char *key_start = requested_uri + 5; // Skip "/api/" - char key[256] = {0}; - strncpy(key, key_start, sizeof(key) - 1); - - UT_CONTROL_PLANE_DEBUG("Extracted Key: %s\n", key); - - // Extract the Accept header - char accept_header[128] = {0}; - if (lws_hdr_copy(wsi, accept_header, sizeof(accept_header), WSI_TOKEN_HTTP_ACCEPT) > 0) - { - UT_CONTROL_PLANE_DEBUG("Accept Header: %s\n", accept_header); - } - else - { - UT_CONTROL_PLANE_ERROR("Missing Accept header\n"); - - const char *error_response_json = "{\"error\": \"Missing Accept header\"}"; - const char *error_response_yaml = "error: Missing Accept header\n"; - - // Default to JSON if Accept header is missing - const char *response_format = "application/json"; - const char *error_response = error_response_json; - - if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response_format = "application/x-yaml"; - error_response = error_response_yaml; - } - - if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) - return -1; - return -1; - } - - // Check if key is valid - if (strlen(key) == 0) - { - UT_CONTROL_PLANE_ERROR("Missing key in the URI\n"); - - const char *error_response_json = "{\"error\": \"Missing key in URI\"}"; - const char *error_response_yaml = "error: Missing key in URI\n"; - - const char *response_format = "application/json"; - const char *error_response = error_response_json; - - if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response_format = "application/x-yaml"; - error_response = error_response_yaml; - } - - if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) - return -1; - return -1; - } - - // Generate response based on Accept header - char *response = NULL; - if (strncmp(accept_header, "application/json", 16) == 0) - { - response = create_response(pInternal, key, "json"); - } - else if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response = create_response(pInternal, key, "yaml"); - } - else - { - UT_CONTROL_PLANE_ERROR("Unsupported Accept header\n"); - - const char *error_response_json = "{\"error\": \"Unsupported Accept header\"}"; - const char *error_response_yaml = "error: Unsupported Accept header\n"; + // Handle GET request for /api/ - const char *response_format = "application/json"; - const char *error_response = error_response_json; - - if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response_format = "application/x-yaml"; - error_response = error_response_yaml; - } - - if (send_error_response(wsi, HTTP_STATUS_BAD_REQUEST, response_format, error_response) < 0) - return -1; - return -1; - } - - // Check if response generation succeeded - if (response == NULL) - { - UT_CONTROL_PLANE_ERROR("Failed to create response\n"); - - const char *error_response_json = "{\"error\": \"Internal Server Error\"}"; - const char *error_response_yaml = "error: Internal Server Error\n"; - - const char *response_format = "application/json"; - const char *error_response = error_response_json; - - if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response_format = "application/x-yaml"; - error_response = error_response_yaml; - } - - if (send_error_response(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, response_format, error_response) < 0) - return -1; - return -1; - } - - // Add HTTP headers - unsigned char *p = buffer + LWS_PRE, *end = buffer + sizeof(buffer) - 1; - if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, accept_header, strlen(response), &p, end) < 0) - { - free(response); - return -1; // Failed to add headers - } + // Validate Accept header + if (validate_accept_header(wsi, accept_header, sizeof(accept_header)) < 0) + { + return -1; + } - // Finalize headers - if (lws_finalize_http_header(wsi, &p, end) < 0) - { - free(response); - return -1; // Failed to finalize headers - } + // Validate URI + if (strncmp(requested_uri, "/api/", 5) != 0) + { + UT_CONTROL_PLANE_ERROR("Invalid URI: %s\n", requested_uri); + return send_error(wsi, HTTP_STATUS_NOT_FOUND, accept_header, + "{\"error\": \"Internal Server Error\"}", + "error: Internal Server Error\n"); + } - // Write headers - if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) - { - free(response); - return -1; // Failed to write headers - } + // Extract key + char key[256] = {0}; + if (extract_key(requested_uri, key, sizeof(key)) < 0) + { + return send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Missing key in URI\"}", + "error: Missing key in URI\n"); + } - // Write body - if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) - { - free(response); - return -1; // Failed to write body - } + // Determine response format + char *response = determine_response_format(pInternal, key, accept_header); + if (response == NULL) + { + return send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Internal Server Error\"}", + "error: Internal Server Error\n"); + } + // Send response + unsigned char *p = buffer + LWS_PRE, *end = buffer + sizeof(buffer) - 1; + if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK, accept_header, strlen(response), &p, end) < 0) + { free(response); - - return 1; // HTTP request handled successfully + return -1; } - else - { - UT_CONTROL_PLANE_ERROR("Invalid URI: %s\n", requested_uri); - const char *error_response_json = "{\"error\": \"Invalid URI\"}"; - const char *error_response_yaml = "error: Invalid URI\n"; - - const char *response_format = "application/json"; - const char *error_response = error_response_json; + if (lws_finalize_http_header(wsi, &p, end) < 0) + { + free(response); + return -1; + } - if (strncmp(accept_header, "application/x-yaml", 18) == 0) - { - response_format = "application/x-yaml"; - error_response = error_response_yaml; - } + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { + free(response); + return -1; + } - if (send_error_response(wsi, HTTP_STATUS_NOT_FOUND, response_format, error_response) < 0) - return -1; + if (lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP_FINAL) < 0) + { + free(response); return -1; } + free(response); + return 1; // HTTP request handled successfully + break; } case LWS_CALLBACK_HTTP_BODY: @@ -779,40 +739,40 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl return UT_CONTROL_PLANE_STATUS_OK; } -ut_control_plane_status_t UT_ControlPlane_RegisterStringCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_string_callback_t callbackFunction, void *userData) +ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler(ut_controlPlane_instance_t *pInstance, char *restAPI, ut_control_REST_API_callback_t callbackFunction, void *userData) + { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; - if ( pInternal == NULL ) + if (pInternal == NULL) { UT_CONTROL_PLANE_ERROR("Invalid Handle\n"); return UT_CONTROL_PLANE_STATUS_INVALID_HANDLE; } - if ( key == NULL ) + if (restAPI == NULL) { UT_CONTROL_PLANE_ERROR("Invalid Param\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if ( callbackFunction == NULL ) + if (callbackFunction == NULL) { UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if ( userData == NULL ) + if (userData == NULL) { UT_CONTROL_PLANE_ERROR("NULL userData\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - - if ( pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES ) + if (pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES) { return UT_CONTROL_PLANE_STATUS_LIST_FULL; } - strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, key,UT_KVP_MAX_ELEMENT_SIZE); + strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, restAPI, UT_KVP_MAX_ELEMENT_SIZE); pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = NULL; pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = callbackFunction; diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 739a67e..00feb06 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -54,7 +54,7 @@ const static ut_control_keyStringMapping_t numericMaptable [] = { }; void testYAMLCallback(char *key, ut_kvp_instance_t *instance, void* userData); -char* testGETCallback(char *key, ut_kvp_instance_t *instance, void* userData, const char* format); +char* testGETCallback(char *key, void* userData); /* L1 Function tests */ @@ -221,17 +221,10 @@ void testJSONCallback(char *key, ut_kvp_instance_t *instance, void* userData) gMessageRecievedJSON = true; } -char* testGETCallback(char *key, ut_kvp_instance_t *instance, void* userData, const char* format) +char* testGETCallback(char *key, void* userData) { - char *kvpData; - printf("*******************************Inside testGETCallback************************\n"); - kvpData = ut_kvp_getDataOfType(instance, format); - - if (kvpData == NULL) - { - return NULL; - } - return kvpData; + printf("*******************************Inside testGETCallback*******************************\n"); + return (char*) userData; } static void UT_ControlPlane_Sigint_Handler(int sig) @@ -266,6 +259,17 @@ static void test_ut_control_performStart() gMessageRecievedYAML = false; + if (read_file_into_memory(UT_CONTROL_GET_FILE_JSON, &gUserDataGetJson) == 0) + { + if (gUserDataGetJson.buffer != NULL) + { + printf("Original Json file\n%s", (char*)gUserDataGetJson.buffer); + } + + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETCallback - Positive \n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &testGETCallback, (void *)gUserDataGetJson.buffer); + } + UT_ControlPlane_Start(gInstance); /* This should still work after start */ @@ -289,19 +293,8 @@ static void test_ut_control_performStart() printf("Original Yaml file\n%s", (char*)gUserDataGetYaml.buffer); } - UT_LOG("UT_ControlPlane_RegisterStringCallbackOnMessage() client testGETCallback - Positive \n"); - UT_ControlPlane_RegisterStringCallbackOnMessage(gInstance, "/v1/callMyFunction", &testGETCallback, (void *)gUserDataGetYaml.buffer); - } - - if (read_file_into_memory(UT_CONTROL_GET_FILE_JSON, &gUserDataGetJson) == 0) - { - if (gUserDataGetJson.buffer != NULL) - { - printf("Original Json file\n%s", (char*)gUserDataGetJson.buffer); - } - - UT_LOG("UT_ControlPlane_RegisterStringCallbackOnMessage() client testGETCallback - Positive \n"); - UT_ControlPlane_RegisterStringCallbackOnMessage(gInstance, "/v1/callMyFunction2", &testGETCallback, (void *)gUserDataGetJson.buffer); + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETCallback - Positive \n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction", &testGETCallback, (void *)gUserDataGetYaml.buffer); } } diff --git a/tests/websocket-clients/test_script_for_curl_request.sh b/tests/websocket-clients/test_script_for_curl_request.sh index 07d88ef..8e6882e 100755 --- a/tests/websocket-clients/test_script_for_curl_request.sh +++ b/tests/websocket-clients/test_script_for_curl_request.sh @@ -45,7 +45,7 @@ hobbies: "traveling" ] }' - ["./curl-get-client-no-header.sh"]='{"error": "Unsupported Accept header"}' + ["./curl-get-client-no-header.sh"]='{"error": "Missing or Invalid Accept header"}' ["./curl-push-client-binary.sh"]="" ["./curl-push-client-json.sh"]="" ["./curl-push-client-yaml.sh"]="" From d710c526bbf31ee58b75e55b7be74d9bc03914aa Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Fri, 31 Jan 2025 21:54:00 +0000 Subject: [PATCH 5/9] Fix gh66 : Fix the naming conventions and further review comments --- .vscode/settings.json | 3 +- include/ut_control_plane.h | 42 +++++--- src/ut_control_plane.c | 85 ++++++++++----- tests/src/ut_test_control_plane.c | 169 +++++++++++++++++++++++------- 4 files changed, 222 insertions(+), 77 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bf1564f..7a92065 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -71,7 +71,8 @@ "type_traits": "c", "utility": "c", "istream": "c", - "ostream": "c" + "ostream": "c", + "libwebsockets.h": "c" }, "cmake.configureOnOpen": true } \ No newline at end of file diff --git a/include/ut_control_plane.h b/include/ut_control_plane.h index a787dea..1858d81 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -45,10 +45,17 @@ typedef struct int32_t value; } ut_control_keyStringMapping_t; +typedef enum +{ + POST = 0, + GET, + INVALID +}eRestApi_t; + typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ /** - * @brief Callback function type for handling control plane POST triggers. + * @brief Callback function type for handling REST_API from POST triggers. * * This callback function is invoked when a POST request is received * at a registered endpoint and the triggerKey is matched on the incoming data. @@ -57,10 +64,10 @@ typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance * @param instance The key-value pair instance containing the incoming data. * @param userData User-defined data passed to the callback function. */ -typedef void (*ut_control_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); +typedef void (*ut_control_REST_API_POST_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); /** - * @brief Callback function type for handling control plane GET API calls. + * @brief Callback function for handling REST_API from GET triggers. * * This callback function is invoked when a GET request is received * at a registered endpoint. It allows the user to implement the @@ -71,7 +78,15 @@ typedef void (*ut_control_callback_t)(char *triggerKey, ut_kvp_instance_t *insta * * @returns A character string containing the result of the API call, in JSON or YAML format */ -typedef char *(*ut_control_REST_API_callback_t)(char *restAPI, void *userData); +typedef char *(*ut_control_REST_API_GET_callback_t)(char *restAPI, void *userData); + +typedef struct +{ + ut_control_REST_API_GET_callback_t callbackFunctionGET; + ut_control_REST_API_POST_callback_t callbackFunctionPOST; + eRestApi_t restApiType; // POST = 0, GET = 1 + void *userData; // user-defined data +} ut_control_rest_api_handler_t; /** * @brief Initializes a control plane instance. @@ -86,36 +101,35 @@ ut_controlPlane_instance_t* UT_ControlPlane_Init( uint32_t monitorPort ); * @param key - Null-terminated string representing the message key to trigger the callback. * @param callbackFunction - Callback function to be invoked when the key is received. * @param userData - Handle to the caller instance. + * @param restApiType - Type of REST API to be registered.(POST = 0, GET = 1) * @returns Status of the registration operation (`ut_control_plane_status_t`). * @retval UT_CONTROL_PLANE_STATUS_OK - Success * @retval UT_CONTROL_PLANE_STATUS_INVALID_HANDLE - Invalid control plane instance handle. * @retval UT_CONTROL_PLANE_STATUS_INVALID_PARAM - Invalid parameter passed * @retval UT_CONTROL_PLANE_STATUS_CALLBACK_LIST_FULL - Callback list is full + * *******************NOTE: This function will be deprecated in future major releases.******************* */ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, - ut_control_callback_t callbackFunction, - void *userData); + ut_control_REST_API_POST_callback_t callbackFunction, + void *userData, eRestApi_t restApiType); /** - * @brief Registers a callback function to handle requests for a specific REST API GET endpoint. + * @brief Registers a callback function for REST API endpoint. * * This function registers a callback function that will be invoked when a request - * is received for the specified REST API endpoint. The callback function will be - * responsible for parsing the request, processing it, and generating a response. + * is received for the specified REST API endpoint. * * @param pInstance A pointer to the control plane instance. - * @param restAPI The name of the REST API GET endpoint. - * @param callbackFunction The callback function to be invoked. - * @param userData User-defined data to be passed to the callback function. + * @param restAPI The name of the REST API endpoint in case of GET or message key for POST. + * @param handler A structure containing callback functions and metadata. * * @returns A status code indicating the success or failure of the registration. */ ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( ut_controlPlane_instance_t *pInstance, char *restAPI, - ut_control_REST_API_callback_t callbackFunction, - void *userData); + ut_control_rest_api_handler_t *handler); /** * @brief Starts the control plane listening for incoming messages. diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index 4573e28..324470b 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -40,9 +40,10 @@ typedef struct { char key[UT_KVP_MAX_ELEMENT_SIZE]; - ut_control_callback_t pCallback; - ut_control_REST_API_callback_t pStringCallback; + ut_control_REST_API_POST_callback_t pCallback; + ut_control_REST_API_GET_callback_t pStringCallback; void* userData; + eRestApi_t pRestApi; }CallbackEntry_t; typedef enum @@ -87,7 +88,8 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); #define MAX_POST_DATA_SIZE 4096 -struct per_session_data__http { +struct per_session_data_http +{ char post_data[MAX_POST_DATA_SIZE]; int post_data_len; }; @@ -158,7 +160,7 @@ static void call_callback_on_match(cp_message_t *mssg, ut_cp_instance_internal_t status = ut_kvp_openMemory(pkvpInstance, mssg->message, mssg->size ); if (status != UT_KVP_STATUS_SUCCESS) { - UT_CONTROL_PLANE_ERROR("ut_kvp_open() - Read Failure\n"); + UT_CONTROL_PLANE_ERROR("ut_kvp_openMemory() - Read Failure\n"); ut_kvp_destroyInstance(pkvpInstance); return; } @@ -322,6 +324,7 @@ static char* create_response(ut_cp_instance_internal_t *pInternal, const char* k kvpData = entry.pStringCallback((char *)key, entry.userData); pkvpInstance = ut_kvp_createInstance(); + // The `kvpData` memory passed gets freed as part of destroy instance status = ut_kvp_openMemory(pkvpInstance, kvpData, strlen(kvpData)); if (status != UT_KVP_STATUS_SUCCESS) { @@ -345,19 +348,27 @@ static int send_error_response(struct lws *wsi, int status, const char *content_ // Add HTTP headers if (lws_add_http_common_headers(wsi, status, content_type, strlen(body), &p, end) < 0) + { return -1; + } // Finalize headers if (lws_finalize_http_header(wsi, &p, end) < 0) + { return -1; + } // Write headers if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { return -1; + } // Write body if (lws_write(wsi, (unsigned char *)body, strlen(body), LWS_WRITE_HTTP_FINAL) < 0) + { return -1; + } return 0; } @@ -367,6 +378,7 @@ static int send_error(void *wsi, int status, const char *accept_header, const ch { const char *response_format = "application/json"; const char *error_response = json_msg; + int result; if (strncmp(accept_header, "application/x-yaml", 18) == 0) { @@ -374,7 +386,8 @@ static int send_error(void *wsi, int status, const char *accept_header, const ch error_response = yaml_msg; } - return send_error_response(wsi, status, response_format, error_response) < 0 ? -1 : -1; + result = send_error_response(wsi, status, response_format, error_response) < 0 ? -1 : -1; + return result; } // Function to validate Accept header @@ -416,18 +429,17 @@ static char *determine_response_format(void *pInternal, const char *key, const c { return create_response(pInternal, key, "yaml"); } - else - { - UT_CONTROL_PLANE_ERROR("Internal Server Error\n"); - return NULL; - } + + UT_CONTROL_PLANE_ERROR("Internal Server Error\n"); + return NULL; } static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { cp_message_t msg; + int result = 0; ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)lws_context_user(lws_get_context(wsi)); - struct per_session_data__http *perSessionData = (struct per_session_data__http *)user; + struct per_session_data_http *perSessionData = (struct per_session_data_http *)user; switch (reason) { @@ -442,9 +454,9 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri); - // Handle POST request for /api/postRequest - if (strcmp(requested_uri, "/api/postRequest") == 0) - { + // Handle POST request based on Token-Type + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { + lwsl_user("Received a POST request\n"); lws_callback_on_writable(wsi); return 0; // Let the body handling process continue } @@ -461,27 +473,30 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void if (strncmp(requested_uri, "/api/", 5) != 0) { UT_CONTROL_PLANE_ERROR("Invalid URI: %s\n", requested_uri); - return send_error(wsi, HTTP_STATUS_NOT_FOUND, accept_header, + result = send_error(wsi, HTTP_STATUS_NOT_FOUND, accept_header, "{\"error\": \"Internal Server Error\"}", "error: Internal Server Error\n"); + return result; } // Extract key char key[256] = {0}; if (extract_key(requested_uri, key, sizeof(key)) < 0) { - return send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + result = send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, "{\"error\": \"Missing key in URI\"}", "error: Missing key in URI\n"); + return result; } // Determine response format char *response = determine_response_format(pInternal, key, accept_header); if (response == NULL) { - return send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + result = send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, "{\"error\": \"Internal Server Error\"}", "error: Internal Server Error\n"); + return result; } // Send response @@ -588,7 +603,7 @@ static struct lws_protocols protocols[] = { { "http-only", callback_http, - sizeof(struct per_session_data__http), + sizeof(struct per_session_data_http), MAX_POST_DATA_SIZE, }, { NULL, NULL, 0, 0 } @@ -697,7 +712,7 @@ void UT_ControlPlane_Stop( ut_controlPlane_instance_t *pInstance ) pInternal->state_machine_thread_handle = 0; } -ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_callback_t callbackFunction, void *userData) +ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_REST_API_POST_callback_t callbackFunction, void *userData, eRestApi_t restApiType) { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; @@ -719,12 +734,17 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if ( userData == NULL ) + if ( userData == NULL ) { UT_CONTROL_PLANE_ERROR("NULL userData\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } + if ( restApiType == INVALID ) + { + UT_CONTROL_PLANE_ERROR("Invalid Rest API\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } if ( pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES ) { @@ -734,12 +754,16 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = callbackFunction; pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = NULL; + pInternal->callbackEntryList[pInternal->callback_entry_index].pRestApi = restApiType; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; } -ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler(ut_controlPlane_instance_t *pInstance, char *restAPI, ut_control_REST_API_callback_t callbackFunction, void *userData) +ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( + ut_controlPlane_instance_t *pInstance, + char *restAPI, + ut_control_rest_api_handler_t *handler) { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; @@ -756,26 +780,33 @@ ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler(ut_controlP return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if (callbackFunction == NULL) + if (handler->callbackFunctionGET == NULL && handler->callbackFunctionPOST == NULL) { - UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); + UT_CONTROL_PLANE_ERROR("NULL callbackFunctions\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if (userData == NULL) + if (handler->userData == NULL && handler->restApiType == POST) { UT_CONTROL_PLANE_ERROR("NULL userData\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } + if (handler->restApiType == INVALID) + { + UT_CONTROL_PLANE_ERROR("Invalid Rest API\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } + if (pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES) { return UT_CONTROL_PLANE_STATUS_LIST_FULL; } strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, restAPI, UT_KVP_MAX_ELEMENT_SIZE); - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = NULL; - pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; - pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = callbackFunction; + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = handler->callbackFunctionPOST; + pInternal->callbackEntryList[pInternal->callback_entry_index].userData = handler->userData; + pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = handler->callbackFunctionGET; + pInternal->callbackEntryList[pInternal->callback_entry_index].pRestApi = handler->restApiType; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 00feb06..9b205c3 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -45,7 +45,7 @@ static UT_test_suite_t *gpAssertSuite3 = NULL; static ut_controlPlane_instance_t *gInstance = NULL; static volatile bool gMessageRecievedYAML = false; static volatile bool gMessageRecievedJSON = false; -static test_ut_memory_t gUserDataYaml, gUserDataJson, gUserDataGetJson, gUserDataGetYaml; +static test_ut_memory_t gUserDataYaml, gUserDataJson; const static ut_control_keyStringMapping_t numericMaptable [] = { { "one", (int32_t)1 }, @@ -54,7 +54,8 @@ const static ut_control_keyStringMapping_t numericMaptable [] = { }; void testYAMLCallback(char *key, ut_kvp_instance_t *instance, void* userData); -char* testGETCallback(char *key, void* userData); +char* testGETJSONCallback(char *restApi, void* userData); +char* testGETYamlCallback(char *restApi, void* userData); /* L1 Function tests */ @@ -136,32 +137,49 @@ static void test_ut_control_l1_regsiterCallback() pInstance = UT_ControlPlane_Init(9000); UT_ASSERT(pInstance != NULL); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, NULL, &testYAMLCallback, userData); + ut_control_rest_api_handler_t handler = { + .callbackFunctionGET = &testGETJSONCallback, + .callbackFunctionPOST = &testYAMLCallback, + .userData = userData, + .restApiType = POST + }; + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, NULL, &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", NULL, userData); + handler.callbackFunctionGET = NULL; + handler.callbackFunctionPOST = NULL; + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, NULL); + handler.callbackFunctionGET = &testGETYamlCallback; + handler.callbackFunctionPOST = &testYAMLCallback; + handler.userData = NULL; + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterCallbackOnMessage(NULL, "test/yamlData", &testYAMLCallback, userData); + handler.userData = userData; + handler.restApiType = INVALID; + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); + + handler.restApiType = POST; + status = UT_ControlPlane_RegisterAPIEndpointHandler(NULL, "test/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "ttest/yamlData", &testYAMLCallback, userData); + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "ttest/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 1; i++ ) { - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); } free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); + status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_LIST_FULL); free(userData); //freeing the userData after registration @@ -221,10 +239,77 @@ void testJSONCallback(char *key, ut_kvp_instance_t *instance, void* userData) gMessageRecievedJSON = true; } -char* testGETCallback(char *key, void* userData) +char* testGETJSONCallback(char *restApi, void* userData) { - printf("*******************************Inside testGETCallback*******************************\n"); - return (char*) userData; + printf("*******************************Inside testGETJSONCallback*******************************\n"); + char *jsonString = (char*)malloc(512); // Adjust size as needed + if (!jsonString) { + return NULL; // Memory allocation failed + } + + // Construct the JSON string using sprintf + sprintf(jsonString, + "{\n" + " \"name\": \"John Doe\",\n" + " \"age\": %d,\n" + " \"email\": \"%s\",\n" + " \"isMarried\": %s,\n" + " \"children\": [\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " },\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " }\n" + " ],\n" + " \"hobbies\": [\n" + " \"%s\",\n" + " \"%s\",\n" + " \"%s\"\n" + " ]\n" + "}", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling" + ); + + return jsonString; // Return the allocated JSON string +} + +char* testGETYamlCallback(char *restApi, void* userData) +{ + printf("*******************************Inside testGETYamlCallback*******************************\n"); + char *yamlString = (char*)malloc(512); // Adjust size as needed + if (!yamlString) { + return NULL; // Memory allocation failed + } + + // Construct the YAML string using sprintf + sprintf(yamlString, + "---\n" + "name: John Doe\n" + "age: %d\n" + "email: %s\n" + "isMarried: %s\n" + "children:\n" + " - name: %s\n" + " age: %d\n" + " - name: %s\n" + " age: %d\n" + "hobbies:\n" + " - %s\n" + " - %s\n" + " - %s\n", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling" + ); + + return yamlString; // Return the allocated Yaml string } static void UT_ControlPlane_Sigint_Handler(int sig) @@ -243,9 +328,18 @@ static void test_ut_control_performInit( void ) static void test_ut_control_performStart() { + ut_control_rest_api_handler_t handler = { + .callbackFunctionGET = &testGETJSONCallback, + .callbackFunctionPOST = &testYAMLCallback, + .userData = NULL, + .restApiType = INVALID + }; UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Negative\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, NULL); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, NULL, POST); + + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETJSONCallback - Negative\n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &handler); if (read_file_into_memory(UT_CONTROL_YAML_FILE, &gUserDataYaml) == 0) { @@ -253,22 +347,25 @@ static void test_ut_control_performStart() { printf("Original Yaml file\n%s", (char*)gUserDataYaml.buffer); } - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Positive\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, (void *)gUserDataYaml.buffer); + + handler.restApiType = POST; + handler.userData = (void *)gUserDataYaml.buffer; + handler.callbackFunctionPOST = &testYAMLCallback; + handler.callbackFunctionGET = NULL; + + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testYAMLCallback - Positive\n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "test/yamlData", &handler); } gMessageRecievedYAML = false; - if (read_file_into_memory(UT_CONTROL_GET_FILE_JSON, &gUserDataGetJson) == 0) - { - if (gUserDataGetJson.buffer != NULL) - { - printf("Original Json file\n%s", (char*)gUserDataGetJson.buffer); - } + handler.restApiType = GET; + handler.userData = NULL; + handler.callbackFunctionPOST = NULL; + handler.callbackFunctionGET = &testGETJSONCallback; - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETCallback - Positive \n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &testGETCallback, (void *)gUserDataGetJson.buffer); - } + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETJSONCallback - Positive \n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &handler); UT_ControlPlane_Start(gInstance); @@ -280,22 +377,24 @@ static void test_ut_control_performStart() printf("Original Json file\n%s", (char*)gUserDataJson.buffer); } - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testJSONCallback - Positive \n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test2/jsonData1", &testJSONCallback, (void *)gUserDataJson.buffer); + handler.restApiType = POST; + handler.userData = (void *)gUserDataJson.buffer; + handler.callbackFunctionPOST = &testJSONCallback; + handler.callbackFunctionGET = NULL; + + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testJSONCallback - Positive \n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "test2/jsonData1", &handler); } gMessageRecievedJSON = false; - if (read_file_into_memory(UT_CONTROL_GET_FILE_YAML, &gUserDataGetYaml) == 0) - { - if (gUserDataGetYaml.buffer != NULL) - { - printf("Original Yaml file\n%s", (char*)gUserDataGetYaml.buffer); - } + handler.restApiType = GET; + handler.userData = NULL; + handler.callbackFunctionPOST = NULL; + handler.callbackFunctionGET = &testGETYamlCallback; - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETCallback - Positive \n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction", &testGETCallback, (void *)gUserDataGetYaml.buffer); - } + UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETYamlCallback - Positive \n"); + UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction", &handler); } void run_client_function() From 5fedbd3fe7f6c359fda9b1fc599bedea18d96e3f Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:22:41 +0000 Subject: [PATCH 6/9] Add gh66 : Adding additional callback register function for handling GET request --- include/ut_control_plane.h | 51 ++++-------- src/ut_control_plane.c | 58 +++++-------- tests/src/ut_test_control_plane.c | 131 +++++++++++++++--------------- 3 files changed, 107 insertions(+), 133 deletions(-) diff --git a/include/ut_control_plane.h b/include/ut_control_plane.h index 1858d81..7164216 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -45,48 +45,33 @@ typedef struct int32_t value; } ut_control_keyStringMapping_t; -typedef enum -{ - POST = 0, - GET, - INVALID -}eRestApi_t; - typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ /** - * @brief Callback function type for handling REST_API from POST triggers. + * @brief Callback function type for handling POST triggers. * * This callback function is invoked when a POST request is received - * at a registered endpoint and the triggerKey is matched on the incoming data. + * at the ut control server and the triggerKey is matched on the incoming data. * * @param triggerKey The trigger key that was matched. * @param instance The key-value pair instance containing the incoming data. * @param userData User-defined data passed to the callback function. */ -typedef void (*ut_control_REST_API_POST_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); +typedef void (*ut_control_on_message_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); /** * @brief Callback function for handling REST_API from GET triggers. * * This callback function is invoked when a GET request is received - * at a registered endpoint. It allows the user to implement the - * REST API call. + * at UT control server and the rest api name of the GET request matches the restAPI parameter + * registered with the UT control server. * * @param restAPI The name of the REST API being called. * @param userData User-defined data passed to the callback function. * - * @returns A character string containing the result of the API call, in JSON or YAML format + * @returns A character string containing the result of the API call */ -typedef char *(*ut_control_REST_API_GET_callback_t)(char *restAPI, void *userData); - -typedef struct -{ - ut_control_REST_API_GET_callback_t callbackFunctionGET; - ut_control_REST_API_POST_callback_t callbackFunctionPOST; - eRestApi_t restApiType; // POST = 0, GET = 1 - void *userData; // user-defined data -} ut_control_rest_api_handler_t; +typedef char *(*ut_control_endpoint_callback_t)(char *restAPI, void *userData); /** * @brief Initializes a control plane instance. @@ -96,23 +81,21 @@ typedef struct ut_controlPlane_instance_t* UT_ControlPlane_Init( uint32_t monitorPort ); /** - * @brief Registers a callback function for a specific message key. + * @brief Registers a callback function to pattern match a key from the POST request * @param pInstance - Handle to the control plane instance. * @param key - Null-terminated string representing the message key to trigger the callback. * @param callbackFunction - Callback function to be invoked when the key is received. * @param userData - Handle to the caller instance. - * @param restApiType - Type of REST API to be registered.(POST = 0, GET = 1) * @returns Status of the registration operation (`ut_control_plane_status_t`). * @retval UT_CONTROL_PLANE_STATUS_OK - Success * @retval UT_CONTROL_PLANE_STATUS_INVALID_HANDLE - Invalid control plane instance handle. * @retval UT_CONTROL_PLANE_STATUS_INVALID_PARAM - Invalid parameter passed * @retval UT_CONTROL_PLANE_STATUS_CALLBACK_LIST_FULL - Callback list is full - * *******************NOTE: This function will be deprecated in future major releases.******************* */ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, - ut_control_REST_API_POST_callback_t callbackFunction, - void *userData, eRestApi_t restApiType); + ut_control_on_message_callback_t callbackFunction, + void *userData); /** * @brief Registers a callback function for REST API endpoint. @@ -122,14 +105,16 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl * * @param pInstance A pointer to the control plane instance. * @param restAPI The name of the REST API endpoint in case of GET or message key for POST. - * @param handler A structure containing callback functions and metadata. - * - * @returns A status code indicating the success or failure of the registration. + * @param userData NULL by default. Optionally, can be used as a handle to the caller instance. + * @returns Status of the registration operation (`ut_control_plane_status_t`). + * @retval UT_CONTROL_PLANE_STATUS_OK - Success + * @retval UT_CONTROL_PLANE_STATUS_INVALID_HANDLE - Invalid control plane instance handle. + * @retval UT_CONTROL_PLANE_STATUS_INVALID_PARAM - Invalid parameter passed + * @retval UT_CONTROL_PLANE_STATUS_CALLBACK_LIST_FULL - Callback list is full */ -ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( +ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback( ut_controlPlane_instance_t *pInstance, - char *restAPI, - ut_control_rest_api_handler_t *handler); + char *restAPI, ut_control_endpoint_callback_t callbackFunction, void *userData); /** * @brief Starts the control plane listening for incoming messages. diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index 324470b..bceef55 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -39,12 +39,16 @@ typedef struct { - char key[UT_KVP_MAX_ELEMENT_SIZE]; - ut_control_REST_API_POST_callback_t pCallback; - ut_control_REST_API_GET_callback_t pStringCallback; - void* userData; - eRestApi_t pRestApi; -}CallbackEntry_t; + ut_control_on_message_callback_t pCallback; + ut_control_endpoint_callback_t pStringCallback; +}Callback_type_t; + +typedef struct +{ + char key[UT_KVP_MAX_ELEMENT_SIZE]; + Callback_type_t pCallbackType; + void *userData; +} CallbackEntry_t; typedef enum { @@ -170,7 +174,7 @@ static void call_callback_on_match(cp_message_t *mssg, ut_cp_instance_internal_t if (UT_KVP_STATUS_SUCCESS == ut_kvp_getStringField(pkvpInstance, entry.key, result_kvp, UT_KVP_MAX_ELEMENT_SIZE)) { // call callback - entry.pCallback(entry.key, pkvpInstance, entry.userData); + entry.pCallbackType.pCallback(entry.key, pkvpInstance, entry.userData); } } ut_kvp_destroyInstance(pkvpInstance); @@ -321,7 +325,7 @@ static char* create_response(ut_cp_instance_internal_t *pInternal, const char* k if (compareStrings(entry.key, key) == 0) { - kvpData = entry.pStringCallback((char *)key, entry.userData); + kvpData = entry.pCallbackType.pStringCallback((char *)key, entry.userData); pkvpInstance = ut_kvp_createInstance(); // The `kvpData` memory passed gets freed as part of destroy instance @@ -712,7 +716,7 @@ void UT_ControlPlane_Stop( ut_controlPlane_instance_t *pInstance ) pInternal->state_machine_thread_handle = 0; } -ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_REST_API_POST_callback_t callbackFunction, void *userData, eRestApi_t restApiType) +ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_on_message_callback_t callbackFunction, void *userData) { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; @@ -740,30 +744,20 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if ( restApiType == INVALID ) - { - UT_CONTROL_PLANE_ERROR("Invalid Rest API\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; - } - if ( pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES ) { return UT_CONTROL_PLANE_STATUS_LIST_FULL; } strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, key,UT_KVP_MAX_ELEMENT_SIZE); - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = callbackFunction; + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pCallback = callbackFunction; pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; - pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = NULL; - pInternal->callbackEntryList[pInternal->callback_entry_index].pRestApi = restApiType; + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pStringCallback = NULL; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; } -ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( - ut_controlPlane_instance_t *pInstance, - char *restAPI, - ut_control_rest_api_handler_t *handler) +ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback(ut_controlPlane_instance_t *pInstance, char *restAPI, ut_control_endpoint_callback_t callbackFunction, void *userData) { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; @@ -780,22 +774,15 @@ ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if (handler->callbackFunctionGET == NULL && handler->callbackFunctionPOST == NULL) + if (callbackFunction == NULL) { - UT_CONTROL_PLANE_ERROR("NULL callbackFunctions\n"); + UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if (handler->userData == NULL && handler->restApiType == POST) + if (userData == NULL) { UT_CONTROL_PLANE_ERROR("NULL userData\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; - } - - if (handler->restApiType == INVALID) - { - UT_CONTROL_PLANE_ERROR("Invalid Rest API\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } if (pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES) @@ -803,10 +790,9 @@ ut_control_plane_status_t UT_ControlPlane_RegisterAPIEndpointHandler( return UT_CONTROL_PLANE_STATUS_LIST_FULL; } strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, restAPI, UT_KVP_MAX_ELEMENT_SIZE); - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = handler->callbackFunctionPOST; - pInternal->callbackEntryList[pInternal->callback_entry_index].userData = handler->userData; - pInternal->callbackEntryList[pInternal->callback_entry_index].pStringCallback = handler->callbackFunctionGET; - pInternal->callbackEntryList[pInternal->callback_entry_index].pRestApi = handler->restApiType; + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pCallback = NULL; + pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pStringCallback = callbackFunction; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 9b205c3..8fd0859 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -41,6 +41,7 @@ static UT_test_suite_t *gpAssertSuite1 = NULL; static UT_test_suite_t *gpAssertSuite2 = NULL; static UT_test_suite_t *gpAssertSuite3 = NULL; +static UT_test_suite_t *gpAssertSuite4 = NULL; static ut_controlPlane_instance_t *gInstance = NULL; static volatile bool gMessageRecievedYAML = false; @@ -126,66 +127,91 @@ static void test_ut_control_l1_testStartStop() UT_LOG("test_ut_control_l1_testStartStop\n"); } -static void test_ut_control_l1_regsiterCallback() +static void test_ut_control_l1_regsiter_on_message_Callback() { ut_controlPlane_instance_t *pInstance; ut_control_plane_status_t status; void* userData = (void* )strdup("testJSONCallbackStringInvalidParam"); - UT_LOG("\ntest_ut_control_l1_regsiterCallback\n"); + UT_LOG("\test_ut_control_l1_regsiter_on_message_Callback\n"); pInstance = UT_ControlPlane_Init(9000); UT_ASSERT(pInstance != NULL); - ut_control_rest_api_handler_t handler = { - .callbackFunctionGET = &testGETJSONCallback, - .callbackFunctionPOST = &testYAMLCallback, - .userData = userData, - .restApiType = POST - }; - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, NULL, &handler); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, NULL, &testYAMLCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - handler.callbackFunctionGET = NULL; - handler.callbackFunctionPOST = NULL; - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", NULL, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - handler.callbackFunctionGET = &testGETYamlCallback; - handler.callbackFunctionPOST = &testYAMLCallback; - handler.userData = NULL; - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, NULL); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - handler.userData = userData; - handler.restApiType = INVALID; - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterCallbackOnMessage(NULL, "test/yamlData", &testYAMLCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); + + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "ttest/yamlData", &testYAMLCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); + free(userData); //freeing the userData after registration + + userData = (void* )strdup("testJSONCallbackString"); + for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 1; i++ ) + { + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); + } + free(userData); //freeing the userData after registration + + userData = (void* )strdup("testJSONCallbackString"); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_LIST_FULL); + free(userData); //freeing the userData after registration + + UT_ControlPlane_Exit(pInstance); + + UT_LOG("test_ut_control_l1_regsiter_on_message_Callback\n"); +} + +static void test_ut_control_l1_regsiter_endpoint_Callback() +{ + ut_controlPlane_instance_t *pInstance; + ut_control_plane_status_t status; + void* userData = (void* )strdup("testJSONCallbackStringInvalidParam"); + + UT_LOG("\ntest_ut_control_l1_regsiter_endpoint_Callback\n"); + + pInstance = UT_ControlPlane_Init(9000); + UT_ASSERT(pInstance != NULL); + + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, NULL, &testGETJSONCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); + + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", NULL, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - handler.restApiType = POST; - status = UT_ControlPlane_RegisterAPIEndpointHandler(NULL, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterEndPointCallback(NULL, "/v1/callMyFunction2", &testGETJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "ttest/yamlData", &handler); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 1; i++ ) { - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); } free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); - status = UT_ControlPlane_RegisterAPIEndpointHandler(pInstance, "test/yamlData", &handler); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_LIST_FULL); free(userData); //freeing the userData after registration UT_ControlPlane_Exit(pInstance); - UT_LOG("test_ut_control_l1_regsiterCallback\n"); + UT_LOG("test_ut_control_l1_regsiter_endpoint_Callback\n"); } /* L2 Testing functions */ @@ -328,18 +354,11 @@ static void test_ut_control_performInit( void ) static void test_ut_control_performStart() { - ut_control_rest_api_handler_t handler = { - .callbackFunctionGET = &testGETJSONCallback, - .callbackFunctionPOST = &testYAMLCallback, - .userData = NULL, - .restApiType = INVALID - }; - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Negative\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, NULL, POST); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, NULL); - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETJSONCallback - Negative\n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &handler); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETJSONCallback - Negative\n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction2", NULL, NULL); if (read_file_into_memory(UT_CONTROL_YAML_FILE, &gUserDataYaml) == 0) { @@ -348,24 +367,14 @@ static void test_ut_control_performStart() printf("Original Yaml file\n%s", (char*)gUserDataYaml.buffer); } - handler.restApiType = POST; - handler.userData = (void *)gUserDataYaml.buffer; - handler.callbackFunctionPOST = &testYAMLCallback; - handler.callbackFunctionGET = NULL; - - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testYAMLCallback - Positive\n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "test/yamlData", &handler); + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Positive\n"); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, &gUserDataYaml.buffer); } gMessageRecievedYAML = false; - handler.restApiType = GET; - handler.userData = NULL; - handler.callbackFunctionPOST = NULL; - handler.callbackFunctionGET = &testGETJSONCallback; - - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETJSONCallback - Positive \n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction2", &handler); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETJSONCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction2", &testGETJSONCallback, NULL); UT_ControlPlane_Start(gInstance); @@ -377,24 +386,14 @@ static void test_ut_control_performStart() printf("Original Json file\n%s", (char*)gUserDataJson.buffer); } - handler.restApiType = POST; - handler.userData = (void *)gUserDataJson.buffer; - handler.callbackFunctionPOST = &testJSONCallback; - handler.callbackFunctionGET = NULL; - - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testJSONCallback - Positive \n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "test2/jsonData1", &handler); + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testJSONCallback - Positive \n"); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test2/jsonData1", &testJSONCallback, &gUserDataJson.buffer); } gMessageRecievedJSON = false; - handler.restApiType = GET; - handler.userData = NULL; - handler.callbackFunctionPOST = NULL; - handler.callbackFunctionGET = &testGETYamlCallback; - - UT_LOG("UT_ControlPlane_RegisterAPIEndpointHandler() client testGETYamlCallback - Positive \n"); - UT_ControlPlane_RegisterAPIEndpointHandler(gInstance, "/v1/callMyFunction", &handler); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETYamlCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction", &testGETYamlCallback, NULL); } void run_client_function() @@ -477,9 +476,13 @@ void register_cp_function() gpAssertSuite1 = UT_add_suite("L1 - ut_control function tests", NULL, NULL); assert(gpAssertSuite1 != NULL); UT_add_test(gpAssertSuite1, "ut-cp Init Exit", test_ut_control_l1_testInitExit); - UT_add_test(gpAssertSuite1, "ut-cp register callback", test_ut_control_l1_regsiterCallback); + UT_add_test(gpAssertSuite1, "ut-cp register on message callback", test_ut_control_l1_regsiter_on_message_Callback); UT_add_test(gpAssertSuite1, "ut-cp websocket service", test_ut_control_l1_testStartStop); + gpAssertSuite4 = UT_add_suite("L1 - ut_control function tests for end point cb", (UT_InitialiseFunction_t) test_ut_control_l1_testInitExit, (UT_CleanupFunction_t) test_ut_control_l1_testStartStop); + assert(gpAssertSuite4 != NULL); + UT_add_test(gpAssertSuite4, "ut-cp register end point callback", test_ut_control_l1_regsiter_endpoint_Callback); + /* L2 - ut_control Module tests */ gpAssertSuite2 = UT_add_suite("L2 - ut_control Module tests", NULL, NULL); assert(gpAssertSuite2 != NULL); From 0db710e2f6d7830e5275aef3fb817500c2a1ec13 Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Tue, 11 Feb 2025 10:52:58 +0000 Subject: [PATCH 7/9] Update gh66 : Updated as per review comments --- include/ut_control_plane.h | 76 +++-- src/ut_control_plane.c | 121 +++---- tests/src/ut_test_control_plane.c | 306 ++++++++---------- .../curl-push-client-binary.sh | 4 +- .../curl-push-client-json.sh | 2 +- .../curl-push-client-yaml.sh | 2 +- 6 files changed, 230 insertions(+), 281 deletions(-) diff --git a/include/ut_control_plane.h b/include/ut_control_plane.h index 7164216..88e3c81 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -47,31 +47,26 @@ typedef struct typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ -/** - * @brief Callback function type for handling POST triggers. - * - * This callback function is invoked when a POST request is received - * at the ut control server and the triggerKey is matched on the incoming data. - * - * @param triggerKey The trigger key that was matched. - * @param instance The key-value pair instance containing the incoming data. - * @param userData User-defined data passed to the callback function. - */ -typedef void (*ut_control_on_message_callback_t)(char *triggerKey, ut_kvp_instance_t *instance, void *userData); +/**** NOTE: This function will be deprecated in future major release ****/ +/** @brief Callback function type for handling control plane messages. */ +typedef void (*ut_control_callback_t)( char *key, ut_kvp_instance_t *instance, void *userData ); /** - * @brief Callback function for handling REST_API from GET triggers. + * @brief Callback function for handling HTTP requests to a specific REST API endpoint. * - * This callback function is invoked when a GET request is received - * at UT control server and the rest api name of the GET request matches the restAPI parameter - * registered with the UT control server. + * This callback is invoked by the UT control server when an HTTP request (GET, POST, PUT, DELETE, etc.) + * is received and the requested REST API endpoint matches the `restAPI` parameter. * - * @param restAPI The name of the REST API being called. - * @param userData User-defined data passed to the callback function. + * @param restAPI The name of the REST API endpoint being called. + * @param httpRequestType The HTTP method of the request (e.g., "GET", "POST", "PUT", "DELETE"). + * @param userData User-defined data passed during registration of the callback. This can be used to + * pass context or state to the callback function. + * @param pData Pointer to the key-value pair (KVP) instance containing the data sent with the request. * - * @returns A character string containing the result of the API call + * @return A dynamically allocated character string containing the JSON response from the API endpoint. + * The caller is responsible for freeing the returned string using `free()`. Returns `NULL` on error. */ -typedef char *(*ut_control_endpoint_callback_t)(char *restAPI, void *userData); +typedef char *(*ut_control_endpoint_callback_t)(const char *restAPI, const char *httpRequestType, ut_kvp_instance_t *pData, void *userData); /** * @brief Initializes a control plane instance. @@ -81,7 +76,8 @@ typedef char *(*ut_control_endpoint_callback_t)(char *restAPI, void *userData); ut_controlPlane_instance_t* UT_ControlPlane_Init( uint32_t monitorPort ); /** - * @brief Registers a callback function to pattern match a key from the POST request + * **** NOTE: This function will be deprecated in future major release **** + * @brief Registers a callback function for a specific message key. * @param pInstance - Handle to the control plane instance. * @param key - Null-terminated string representing the message key to trigger the callback. * @param callbackFunction - Callback function to be invoked when the key is received. @@ -94,27 +90,41 @@ ut_controlPlane_instance_t* UT_ControlPlane_Init( uint32_t monitorPort ); */ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, - ut_control_on_message_callback_t callbackFunction, + ut_control_callback_t callbackFunction, void *userData); /** - * @brief Registers a callback function for REST API endpoint. + * @brief Registers a callback for a REST API endpoint (GET) or POST message key. * - * This function registers a callback function that will be invoked when a request - * is received for the specified REST API endpoint. + * Registers a callback function to be invoked when a GET request is made to the + * specified `restAPI` endpoint, or when a POST request is received with + * `restAPI` as the message key. * - * @param pInstance A pointer to the control plane instance. - * @param restAPI The name of the REST API endpoint in case of GET or message key for POST. - * @param userData NULL by default. Optionally, can be used as a handle to the caller instance. - * @returns Status of the registration operation (`ut_control_plane_status_t`). - * @retval UT_CONTROL_PLANE_STATUS_OK - Success - * @retval UT_CONTROL_PLANE_STATUS_INVALID_HANDLE - Invalid control plane instance handle. - * @retval UT_CONTROL_PLANE_STATUS_INVALID_PARAM - Invalid parameter passed - * @retval UT_CONTROL_PLANE_STATUS_CALLBACK_LIST_FULL - Callback list is full + * @param[in] pInstance Pointer to the control plane instance. + * @param[in] httpRequestType The HTTP request type ("GET" or "POST"). + * @param[in] restAPI The REST API endpoint for GET requests, or the message key + * for POST requests. For example, "/users" for a GET + * request, or "status" for a POST request. + * @param[in] callbackFunction Pointer to the callback function. The function + * type depends on the request type: + * `ut_control_endpoint_callback_t` for GET requests, + * or `ut_control_on_message_callback_t` for POST + * requests. + * @param[in] userData Pointer to user-provided data that will be passed to the + * callback function. This can be used, for example, to + * pass a pointer to context data. + * @returns A status code indicating the result of the operation. + * @retval UT_CONTROL_PLANE_STATUS_OK Success. + * @retval UT_CONTROL_PLANE_STATUS_INVALID_HANDLE Invalid `pInstance`. + * @retval UT_CONTROL_PLANE_STATUS_INVALID_PARAM Invalid `restAPI` or + * `callbackFunction`. + * @retval UT_CONTROL_PLANE_STATUS_CALLBACK_LIST_FULL Callback list is full. */ ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback( ut_controlPlane_instance_t *pInstance, - char *restAPI, ut_control_endpoint_callback_t callbackFunction, void *userData); + const char *httpRequestType, + char *restAPI, ut_control_endpoint_callback_t callbackFunction, + void *userData); /** * @brief Starts the control plane listening for incoming messages. diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index bceef55..a598682 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -34,20 +34,16 @@ #define UT_CONTROL_PLANE_DEBUG(f_, ...) UT_LOG_DEBUG((f_), ##__VA_ARGS__) #define MAX_MESSAGES 32 +#define MAX_REQUEST_SIZE 32 #define UT_CP_MAGIC (0xdeadbeef) -typedef struct -{ - ut_control_on_message_callback_t pCallback; - ut_control_endpoint_callback_t pStringCallback; -}Callback_type_t; - typedef struct { char key[UT_KVP_MAX_ELEMENT_SIZE]; - Callback_type_t pCallbackType; + ut_control_endpoint_callback_t pCallback; void *userData; + char requestType[MAX_REQUEST_SIZE]; } CallbackEntry_t; typedef enum @@ -61,6 +57,7 @@ typedef struct eMessage_t status; char *message; uint32_t size; + char key[UT_KVP_MAX_ELEMENT_SIZE]; } cp_message_t; typedef struct @@ -99,6 +96,7 @@ struct per_session_data_http }; #endif static ut_cp_instance_internal_t *validateCPInstance(ut_controlPlane_instance_t *pInstance); +static char gPostKey[UT_KVP_MAX_ELEMENT_SIZE]; /* Local Fucntions*/ static void enqueue_message(cp_message_t *data, ut_cp_instance_internal_t *pInternal ) @@ -109,6 +107,7 @@ static void enqueue_message(cp_message_t *data, ut_cp_instance_internal_t *pInte pInternal->message_queue[pInternal->message_count].size = data->size; pInternal->message_queue[pInternal->message_count].status = data->status; pInternal->message_queue[pInternal->message_count].message = data->message; + strncpy(pInternal->message_queue[pInternal->message_count].key, data->key, UT_KVP_MAX_ELEMENT_SIZE); pInternal->message_count++; pthread_cond_signal(&pInternal->queue_condition); } @@ -137,6 +136,7 @@ static cp_message_t* dequeue_message(ut_cp_instance_internal_t *pInternal) msg->size = pInternal->message_queue[0].size; msg->status = pInternal->message_queue[0].status; msg->message = pInternal->message_queue[0].message; + strncpy(msg->key, pInternal->message_queue[0].key, UT_KVP_MAX_ELEMENT_SIZE); for (int i = 0; i < pInternal->message_count - 1; i++) { @@ -151,34 +151,32 @@ static void call_callback_on_match(cp_message_t *mssg, ut_cp_instance_internal_t { ut_kvp_instance_t *pkvpInstance = NULL; ut_kvp_status_t status; - char result_kvp[UT_KVP_MAX_ELEMENT_SIZE] = {0xff}; - if (mssg->message == NULL) { return; } - pkvpInstance = ut_kvp_createInstance(); - - /* Note: mssg-message data will be freed by the destoryInstance() function */ - status = ut_kvp_openMemory(pkvpInstance, mssg->message, mssg->size ); - if (status != UT_KVP_STATUS_SUCCESS) - { - UT_CONTROL_PLANE_ERROR("ut_kvp_openMemory() - Read Failure\n"); - ut_kvp_destroyInstance(pkvpInstance); - return; - } for (uint32_t i = 0; i < pInternal->callback_entry_index; i++) { CallbackEntry_t entry = pInternal->callbackEntryList[i]; - if (UT_KVP_STATUS_SUCCESS == ut_kvp_getStringField(pkvpInstance, entry.key, result_kvp, UT_KVP_MAX_ELEMENT_SIZE)) + if (strcmp(entry.key, mssg->key) == 0) { - // call callback - entry.pCallbackType.pCallback(entry.key, pkvpInstance, entry.userData); + pkvpInstance = ut_kvp_createInstance(); + + /* Note: mssg-message data will be freed by the destoryInstance() function */ + status = ut_kvp_openMemory(pkvpInstance, mssg->message, mssg->size ); + if (status != UT_KVP_STATUS_SUCCESS) + { + UT_CONTROL_PLANE_ERROR("ut_kvp_openMemory() - Read Failure\n"); + ut_kvp_destroyInstance(pkvpInstance); + return; + } + + entry.pCallback(entry.key, "POST", pkvpInstance, entry.userData); + ut_kvp_destroyInstance(pkvpInstance); + return; } } - ut_kvp_destroyInstance(pkvpInstance); - return; } static void *service_ws_requests(void *data) @@ -325,7 +323,7 @@ static char* create_response(ut_cp_instance_internal_t *pInternal, const char* k if (compareStrings(entry.key, key) == 0) { - kvpData = entry.pCallbackType.pStringCallback((char *)key, entry.userData); + kvpData = entry.pCallback((char *)key, "GET", NULL, entry.userData); pkvpInstance = ut_kvp_createInstance(); // The `kvpData` memory passed gets freed as part of destroy instance @@ -444,23 +442,29 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void int result = 0; ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)lws_context_user(lws_get_context(wsi)); struct per_session_data_http *perSessionData = (struct per_session_data_http *)user; + char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI + char accept_header[128] = {0}; // Buffer for the Accept header switch (reason) { - case LWS_CALLBACK_HTTP: { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); - char *requested_uri = (char *)in; // Use the 'in' parameter to get the URI - char accept_header[128] = {0}; // Buffer for the Accept header unsigned char buffer[LWS_PRE + 1024]; // Allocate buffer for headers and body UT_CONTROL_PLANE_DEBUG("Requested URI: %s\n", requested_uri); // Handle POST request based on Token-Type if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { - lwsl_user("Received a POST request\n"); + UT_CONTROL_PLANE_DEBUG("Received a POST request\n"); + if (extract_key(requested_uri, gPostKey, sizeof(gPostKey)) < 0) + { + result = send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Missing key in URI\"}", + "error: Missing key in URI\n"); + return -1; + } lws_callback_on_writable(wsi); return 0; // Let the body handling process continue } @@ -572,6 +576,9 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void msg.status = DATA_RECIEVED; strncpy(msg.message, (const char *)perSessionData->post_data, perSessionData->post_data_len); msg.message[perSessionData->post_data_len] = '\0'; + msg.key[strlen(msg.key)] = '\0'; + strncpy(msg.key, gPostKey, UT_KVP_MAX_ELEMENT_SIZE); + // UT_CONTROL_PLANE_DEBUG("Received message:\n %s\n", msg.message); enqueue_message(&msg, pInternal); // char response[] = "{\"status\": \"success\"}"; @@ -716,49 +723,12 @@ void UT_ControlPlane_Stop( ut_controlPlane_instance_t *pInstance ) pInternal->state_machine_thread_handle = 0; } -ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_on_message_callback_t callbackFunction, void *userData) +ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_callback_t callbackFunction, void *userData) { - ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; - - if ( pInternal == NULL ) - { - UT_CONTROL_PLANE_ERROR("Invalid Handle\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_HANDLE; - } - - if ( key == NULL ) - { - UT_CONTROL_PLANE_ERROR("Invalid Param\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; - } - - if ( callbackFunction == NULL ) - { - UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; - } - - if ( userData == NULL ) - { - UT_CONTROL_PLANE_ERROR("NULL userData\n"); - return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; - } - - if ( pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES ) - { - return UT_CONTROL_PLANE_STATUS_LIST_FULL; - } - strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, key,UT_KVP_MAX_ELEMENT_SIZE); - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pCallback = callbackFunction; - pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pStringCallback = NULL; - pInternal->callback_entry_index++; - UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); - return UT_CONTROL_PLANE_STATUS_OK; + return UT_ControlPlane_RegisterEndPointCallback(pInstance, "POST", key, (ut_control_endpoint_callback_t)callbackFunction, userData); } -ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback(ut_controlPlane_instance_t *pInstance, char *restAPI, ut_control_endpoint_callback_t callbackFunction, void *userData) - +ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback(ut_controlPlane_instance_t *pInstance, const char *httpRequestType, char *restAPI, ut_control_endpoint_callback_t callbackFunction, void *userData) { ut_cp_instance_internal_t *pInternal = (ut_cp_instance_internal_t *)pInstance; @@ -774,15 +744,22 @@ ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback(ut_controlPla return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } + if (httpRequestType == NULL) + { + UT_CONTROL_PLANE_ERROR("Invalid Param\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; + } + if (callbackFunction == NULL) { UT_CONTROL_PLANE_ERROR("NULL callbackFunction\n"); return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } - if (userData == NULL) + if (userData == NULL && strcmp(httpRequestType, "POST") == 0) { UT_CONTROL_PLANE_ERROR("NULL userData\n"); + return UT_CONTROL_PLANE_STATUS_INVALID_PARAM; } if (pInternal->callback_entry_index >= UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES) @@ -790,9 +767,9 @@ ut_control_plane_status_t UT_ControlPlane_RegisterEndPointCallback(ut_controlPla return UT_CONTROL_PLANE_STATUS_LIST_FULL; } strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].key, restAPI, UT_KVP_MAX_ELEMENT_SIZE); - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pCallback = NULL; + strncpy(pInternal->callbackEntryList[pInternal->callback_entry_index].requestType, httpRequestType, MAX_REQUEST_SIZE); + pInternal->callbackEntryList[pInternal->callback_entry_index].pCallback = callbackFunction; pInternal->callbackEntryList[pInternal->callback_entry_index].userData = userData; - pInternal->callbackEntryList[pInternal->callback_entry_index].pCallbackType.pStringCallback = callbackFunction; pInternal->callback_entry_index++; UT_CONTROL_PLANE_DEBUG("callback_entry_index : %d\n", pInternal->callback_entry_index); return UT_CONTROL_PLANE_STATUS_OK; diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 8fd0859..967c483 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -41,7 +41,6 @@ static UT_test_suite_t *gpAssertSuite1 = NULL; static UT_test_suite_t *gpAssertSuite2 = NULL; static UT_test_suite_t *gpAssertSuite3 = NULL; -static UT_test_suite_t *gpAssertSuite4 = NULL; static ut_controlPlane_instance_t *gInstance = NULL; static volatile bool gMessageRecievedYAML = false; @@ -54,10 +53,8 @@ const static ut_control_keyStringMapping_t numericMaptable [] = { { "three", (int32_t)3 } }; -void testYAMLCallback(char *key, ut_kvp_instance_t *instance, void* userData); -char* testGETJSONCallback(char *restApi, void* userData); -char* testGETYamlCallback(char *restApi, void* userData); - +char* testRestJSONCallback(const char *restApi, const char* requestType, ut_kvp_instance_t *instance, void* userData); +char* testRestYamlCallback(const char *restApi, const char* requestType, ut_kvp_instance_t *instance, void* userData); /* L1 Function tests */ static void test_ut_control_l1_testInitExit() @@ -127,215 +124,184 @@ static void test_ut_control_l1_testStartStop() UT_LOG("test_ut_control_l1_testStartStop\n"); } -static void test_ut_control_l1_regsiter_on_message_Callback() +static void test_ut_control_l1_regsiterCallback() { ut_controlPlane_instance_t *pInstance; ut_control_plane_status_t status; void* userData = (void* )strdup("testJSONCallbackStringInvalidParam"); - UT_LOG("\test_ut_control_l1_regsiter_on_message_Callback\n"); + UT_LOG("\test_ut_control_l1_regsiterCallback\n"); pInstance = UT_ControlPlane_Init(9000); UT_ASSERT(pInstance != NULL); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, NULL, &testYAMLCallback, userData); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, NULL, (ut_control_callback_t)&testRestYamlCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", NULL, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, NULL); + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", (ut_control_callback_t)&testRestYamlCallback, NULL); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterCallbackOnMessage(NULL, "test/yamlData", &testYAMLCallback, userData); + status = UT_ControlPlane_RegisterCallbackOnMessage(NULL, "test/yamlData", (ut_control_callback_t)&testRestYamlCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "ttest/yamlData", &testYAMLCallback, userData); - UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); - free(userData); //freeing the userData after registration - - userData = (void* )strdup("testJSONCallbackString"); - for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 1; i++ ) - { - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); - UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); - } - free(userData); //freeing the userData after registration - - userData = (void* )strdup("testJSONCallbackString"); - status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, userData); - UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_LIST_FULL); - free(userData); //freeing the userData after registration - - UT_ControlPlane_Exit(pInstance); - - UT_LOG("test_ut_control_l1_regsiter_on_message_Callback\n"); -} - -static void test_ut_control_l1_regsiter_endpoint_Callback() -{ - ut_controlPlane_instance_t *pInstance; - ut_control_plane_status_t status; - void* userData = (void* )strdup("testJSONCallbackStringInvalidParam"); - - UT_LOG("\ntest_ut_control_l1_regsiter_endpoint_Callback\n"); - - pInstance = UT_ControlPlane_Init(9000); - UT_ASSERT(pInstance != NULL); - - status = UT_ControlPlane_RegisterEndPointCallback(pInstance, NULL, &testGETJSONCallback, userData); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", NULL, &testRestJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", NULL, userData); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", "/v1/callMyFunction2", NULL, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); - status = UT_ControlPlane_RegisterEndPointCallback(NULL, "/v1/callMyFunction2", &testGETJSONCallback, userData); + status = UT_ControlPlane_RegisterEndPointCallback(NULL, "GET", "/v1/callMyFunction2", &testRestJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); - status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, NULL, "/v1/callMyFunction2", &testRestJSONCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); + + status = UT_ControlPlane_RegisterCallbackOnMessage(pInstance, "ttest/yamlData", (ut_control_callback_t)&testRestYamlCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); + free(userData); //freeing the userData after registration + + userData = (void* )strdup("testRestJSONCallback"); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", "/v1/callMyFunction2", &testRestJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); - for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 1; i++ ) + for (int i = 0; i< UT_CONTROL_PLANE_MAX_CALLBACK_ENTRIES - 2; i++ ) { - status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", "/v1/callMyFunction2", &testRestJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_OK); } free(userData); //freeing the userData after registration userData = (void* )strdup("testJSONCallbackString"); - status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "/v1/callMyFunction2", &testGETJSONCallback, userData); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", "/v1/callMyFunction2", &testRestJSONCallback, userData); UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_LIST_FULL); free(userData); //freeing the userData after registration UT_ControlPlane_Exit(pInstance); - UT_LOG("test_ut_control_l1_regsiter_endpoint_Callback\n"); + UT_LOG("test_ut_control_l1_regsiterCallback\n"); } /* L2 Testing functions */ -void testYAMLCallback(char *key, ut_kvp_instance_t *instance, void* userData) +char* testRestJSONCallback(const char *restApi, const char* requestType, ut_kvp_instance_t *instance, void* userData) { - char* kvpData; - printf("*******************************Inside testYAMLCallback************************\n"); - kvpData = ut_kvp_getData(instance); - char *data = (char*)userData; - - if(kvpData != NULL) + if (strcmp(requestType, "GET") == 0) { - // Print the emitted KVP string - printf("%s\n", kvpData); + UT_LOG("**************testJSONCallback GET is called****************\n"); + char *jsonString = (char *)malloc(512); // Adjust size as needed + if (!jsonString) + { + return NULL; // Memory allocation failed + } - // Free the emitted KVP string - free(kvpData); + // Construct the JSON string using sprintf + sprintf(jsonString, + "{\n" + " \"name\": \"John Doe\",\n" + " \"age\": %d,\n" + " \"email\": \"%s\",\n" + " \"isMarried\": %s,\n" + " \"children\": [\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " },\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " }\n" + " ],\n" + " \"hobbies\": [\n" + " \"%s\",\n" + " \"%s\",\n" + " \"%s\"\n" + " ]\n" + "}", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling"); + + return jsonString; // Return the allocated JSON string } - - if(data != NULL) + else { - printf("Original Yaml file\n%s", data); - } + char *kvpData; + UT_LOG("**************testJSONCallback POST is called****************\n"); + kvpData = ut_kvp_getData(instance); + + if (kvpData != NULL) + { + // Print the emitted KVP string + printf("%s\n", kvpData); - //UT_ASSERT_STRING_EQUAL(kvpData, data); - gMessageRecievedYAML = true; + // Free the emitted KVP string + free(kvpData); + } + + // UT_ASSERT_STRING_EQUAL(kvpData, data); + gMessageRecievedJSON = true; + return NULL; + } } -void testJSONCallback(char *key, ut_kvp_instance_t *instance, void* userData) +char* testRestYamlCallback(const char *restApi, const char* requestType, ut_kvp_instance_t *instance, void* userData) { - char* kvpData; - UT_LOG("**************testJSONCallback is called****************\n"); - kvpData = ut_kvp_getData(instance); - char *data = (char*)userData; - - if(kvpData != NULL) + if (strcmp(requestType, "GET") == 0) { - // Print the emitted KVP string - printf("%s\n", kvpData); + UT_LOG("**************testRestYamlCallback GET is called****************\n"); + char *yamlString = (char *)malloc(512); // Adjust size as needed + if (!yamlString) + { + return NULL; // Memory allocation failed + } - // Free the emitted KVP string - free(kvpData); + // Construct the YAML string using sprintf + sprintf(yamlString, + "---\n" + "name: John Doe\n" + "age: %d\n" + "email: %s\n" + "isMarried: %s\n" + "children:\n" + " - name: %s\n" + " age: %d\n" + " - name: %s\n" + " age: %d\n" + "hobbies:\n" + " - %s\n" + " - %s\n" + " - %s\n", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling"); + + return yamlString; // Return the allocated Yaml string } - - if(data != NULL) + else { - printf("Original Json file\n%s", data); - } + char *kvpData; + UT_LOG("**************testRestYamlCallback POST is called****************\n"); + kvpData = ut_kvp_getData(instance); - //UT_ASSERT_STRING_EQUAL(kvpData, data); - gMessageRecievedJSON = true; -} - -char* testGETJSONCallback(char *restApi, void* userData) -{ - printf("*******************************Inside testGETJSONCallback*******************************\n"); - char *jsonString = (char*)malloc(512); // Adjust size as needed - if (!jsonString) { - return NULL; // Memory allocation failed - } + if (kvpData != NULL) + { + // Print the emitted KVP string + printf("%s\n", kvpData); - // Construct the JSON string using sprintf - sprintf(jsonString, - "{\n" - " \"name\": \"John Doe\",\n" - " \"age\": %d,\n" - " \"email\": \"%s\",\n" - " \"isMarried\": %s,\n" - " \"children\": [\n" - " {\n" - " \"name\": \"%s\",\n" - " \"age\": %d\n" - " },\n" - " {\n" - " \"name\": \"%s\",\n" - " \"age\": %d\n" - " }\n" - " ],\n" - " \"hobbies\": [\n" - " \"%s\",\n" - " \"%s\",\n" - " \"%s\"\n" - " ]\n" - "}", - 30, "johndoe@example.com", "false", - "Alice", 5, - "Bob", 3, - "reading", "cycling", "traveling" - ); - - return jsonString; // Return the allocated JSON string -} + // Free the emitted KVP string + free(kvpData); + } -char* testGETYamlCallback(char *restApi, void* userData) -{ - printf("*******************************Inside testGETYamlCallback*******************************\n"); - char *yamlString = (char*)malloc(512); // Adjust size as needed - if (!yamlString) { - return NULL; // Memory allocation failed + // UT_ASSERT_STRING_EQUAL(kvpData, data); + gMessageRecievedYAML = true; + return NULL; } - - // Construct the YAML string using sprintf - sprintf(yamlString, - "---\n" - "name: John Doe\n" - "age: %d\n" - "email: %s\n" - "isMarried: %s\n" - "children:\n" - " - name: %s\n" - " age: %d\n" - " - name: %s\n" - " age: %d\n" - "hobbies:\n" - " - %s\n" - " - %s\n" - " - %s\n", - 30, "johndoe@example.com", "false", - "Alice", 5, - "Bob", 3, - "reading", "cycling", "traveling" - ); - - return yamlString; // Return the allocated Yaml string } static void UT_ControlPlane_Sigint_Handler(int sig) @@ -354,11 +320,11 @@ static void test_ut_control_performInit( void ) static void test_ut_control_performStart() { - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Negative\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, NULL); + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testRestYamlCallback - Negative\n"); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "postBinaryYaml", (ut_control_callback_t)&testRestYamlCallback, NULL); - UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETJSONCallback - Negative\n"); - UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction2", NULL, NULL); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testRestJSONCallback - Negative\n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, NULL, "/v1/callMyFunction2", NULL, NULL); if (read_file_into_memory(UT_CONTROL_YAML_FILE, &gUserDataYaml) == 0) { @@ -367,14 +333,14 @@ static void test_ut_control_performStart() printf("Original Yaml file\n%s", (char*)gUserDataYaml.buffer); } - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Positive\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, &gUserDataYaml.buffer); + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testRestYamlCallback - Positive\n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "POST", "postYaml", &testRestYamlCallback, &gUserDataYaml.buffer); } gMessageRecievedYAML = false; - UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETJSONCallback - Positive \n"); - UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction2", &testGETJSONCallback, NULL); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testRestJSONCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "GET", "/v1/callMyFunction2", &testRestJSONCallback, NULL); UT_ControlPlane_Start(gInstance); @@ -386,14 +352,14 @@ static void test_ut_control_performStart() printf("Original Json file\n%s", (char*)gUserDataJson.buffer); } - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testJSONCallback - Positive \n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test2/jsonData1", &testJSONCallback, &gUserDataJson.buffer); + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testRestJSONCallback - Positive \n"); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "postJson", (ut_control_callback_t)&testRestJSONCallback, &gUserDataJson.buffer); } gMessageRecievedJSON = false; - UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testGETYamlCallback - Positive \n"); - UT_ControlPlane_RegisterEndPointCallback(gInstance, "/v1/callMyFunction", &testGETYamlCallback, NULL); + UT_LOG("UT_ControlPlane_RegisterEndPointCallback() client testRestYamlCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "GET", "/v1/callMyFunction", &testRestYamlCallback, NULL); } void run_client_function() @@ -476,13 +442,9 @@ void register_cp_function() gpAssertSuite1 = UT_add_suite("L1 - ut_control function tests", NULL, NULL); assert(gpAssertSuite1 != NULL); UT_add_test(gpAssertSuite1, "ut-cp Init Exit", test_ut_control_l1_testInitExit); - UT_add_test(gpAssertSuite1, "ut-cp register on message callback", test_ut_control_l1_regsiter_on_message_Callback); + UT_add_test(gpAssertSuite1, "ut-cp register on message callback", test_ut_control_l1_regsiterCallback); UT_add_test(gpAssertSuite1, "ut-cp websocket service", test_ut_control_l1_testStartStop); - gpAssertSuite4 = UT_add_suite("L1 - ut_control function tests for end point cb", (UT_InitialiseFunction_t) test_ut_control_l1_testInitExit, (UT_CleanupFunction_t) test_ut_control_l1_testStartStop); - assert(gpAssertSuite4 != NULL); - UT_add_test(gpAssertSuite4, "ut-cp register end point callback", test_ut_control_l1_regsiter_endpoint_Callback); - /* L2 - ut_control Module tests */ gpAssertSuite2 = UT_add_suite("L2 - ut_control Module tests", NULL, NULL); assert(gpAssertSuite2 != NULL); diff --git a/tests/websocket-clients/curl-push-client-binary.sh b/tests/websocket-clients/curl-push-client-binary.sh index 2c6f2db..93d713a 100755 --- a/tests/websocket-clients/curl-push-client-binary.sh +++ b/tests/websocket-clients/curl-push-client-binary.sh @@ -1,2 +1,2 @@ -curl -X POST http://localhost:8080/api/postRequest -H "Content-Type: application/octet-stream" --data-binary "@example.yaml" -curl -X POST http://localhost:8080/api/postRequest -H "Content-Type: application/octet-stream" --data-binary "@example.json" \ No newline at end of file +curl -X POST http://localhost:8080/api/postBinaryYaml -H "Content-Type: application/octet-stream" --data-binary "@example.yaml" +curl -X POST http://localhost:8080/api/postBinaryJson -H "Content-Type: application/octet-stream" --data-binary "@example.json" \ No newline at end of file diff --git a/tests/websocket-clients/curl-push-client-json.sh b/tests/websocket-clients/curl-push-client-json.sh index 700cc53..281a539 100755 --- a/tests/websocket-clients/curl-push-client-json.sh +++ b/tests/websocket-clients/curl-push-client-json.sh @@ -1 +1 @@ -curl -X POST -H "Content-Type: application/json" --data "@example.json" http://localhost:8080/api/postRequest \ No newline at end of file +curl -X POST -H "Content-Type: application/json" --data "@example.json" http://localhost:8080/api/postJson \ No newline at end of file diff --git a/tests/websocket-clients/curl-push-client-yaml.sh b/tests/websocket-clients/curl-push-client-yaml.sh index d565f22..54a9141 100755 --- a/tests/websocket-clients/curl-push-client-yaml.sh +++ b/tests/websocket-clients/curl-push-client-yaml.sh @@ -1 +1 @@ -curl -X POST -H "Content-Type: application/x-yaml" --data-binary "@example.yaml" http://localhost:8080/api/postRequest +curl -X POST -H "Content-Type: application/x-yaml" --data-binary "@example.yaml" http://localhost:8080/api/postYaml From 6688fa3d1705a2e64f984bbce577091602883277 Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:03:59 +0000 Subject: [PATCH 8/9] Add gh66 : Adding changes for handling GET requests with query params --- src/ut_control_plane.c | 15 +- tests/src/ut_test_control_plane.c | 153 ++++++++++++------ .../curl-get-filtered-client-json.sh | 1 + .../curl-get-filtered-client-yaml.sh | 1 + .../test_script_for_curl_request.sh | 38 ++++- 5 files changed, 160 insertions(+), 48 deletions(-) create mode 100755 tests/websocket-clients/curl-get-filtered-client-json.sh create mode 100755 tests/websocket-clients/curl-get-filtered-client-yaml.sh diff --git a/src/ut_control_plane.c b/src/ut_control_plane.c index a598682..daa4537 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -97,6 +97,7 @@ struct per_session_data_http #endif static ut_cp_instance_internal_t *validateCPInstance(ut_controlPlane_instance_t *pInstance); static char gPostKey[UT_KVP_MAX_ELEMENT_SIZE]; +static char gQueryString[UT_KVP_MAX_ELEMENT_SIZE]; /* Local Fucntions*/ static void enqueue_message(cp_message_t *data, ut_cp_instance_internal_t *pInternal ) @@ -323,7 +324,14 @@ static char* create_response(ut_cp_instance_internal_t *pInternal, const char* k if (compareStrings(entry.key, key) == 0) { - kvpData = entry.pCallback((char *)key, "GET", NULL, entry.userData); + if (gQueryString[0] != '\0') + { + kvpData = entry.pCallback((char *)key, "GET", gQueryString, entry.userData); + } + else + { + kvpData = entry.pCallback((char *)key, "GET", NULL, entry.userData); + } pkvpInstance = ut_kvp_createInstance(); // The `kvpData` memory passed gets freed as part of destroy instance @@ -497,6 +505,11 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void return result; } + if (lws_hdr_copy(wsi, gQueryString, sizeof(gQueryString), WSI_TOKEN_HTTP_URI_ARGS) > 0) + { + UT_CONTROL_PLANE_DEBUG("Query String: %s\n", gQueryString); + } + // Determine response format char *response = determine_response_format(pInternal, key, accept_header); if (response == NULL) diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 967c483..b2019fb 100644 --- a/tests/src/ut_test_control_plane.c +++ b/tests/src/ut_test_control_plane.c @@ -199,33 +199,67 @@ char* testRestJSONCallback(const char *restApi, const char* requestType, ut_kvp_ } // Construct the JSON string using sprintf - sprintf(jsonString, - "{\n" - " \"name\": \"John Doe\",\n" - " \"age\": %d,\n" - " \"email\": \"%s\",\n" - " \"isMarried\": %s,\n" - " \"children\": [\n" - " {\n" - " \"name\": \"%s\",\n" - " \"age\": %d\n" - " },\n" - " {\n" - " \"name\": \"%s\",\n" - " \"age\": %d\n" - " }\n" - " ],\n" - " \"hobbies\": [\n" - " \"%s\",\n" - " \"%s\",\n" - " \"%s\"\n" - " ]\n" - "}", - 30, "johndoe@example.com", "false", - "Alice", 5, - "Bob", 3, - "reading", "cycling", "traveling"); - + if (instance != NULL) + { + sprintf(jsonString, + "{\n" + " \"name\": \"John Doe\",\n" + " \"age\": %d,\n" + " \"email\": \"%s\",\n" + " \"isMarried\": %s,\n" + " \"children\": [\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " },\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " }\n" + " ],\n" + " \"hobbies\": [\n" + " \"%s\",\n" + " \"%s\",\n" + " \"%s\"\n" + " ]\n" + "pData: %s\n" + "}", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling", (char *)instance); + + UT_LOG("pData = [%s]\n", (char *)instance); + } + else + { + sprintf(jsonString, + "{\n" + " \"name\": \"John Doe\",\n" + " \"age\": %d,\n" + " \"email\": \"%s\",\n" + " \"isMarried\": %s,\n" + " \"children\": [\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " },\n" + " {\n" + " \"name\": \"%s\",\n" + " \"age\": %d\n" + " }\n" + " ],\n" + " \"hobbies\": [\n" + " \"%s\",\n" + " \"%s\",\n" + " \"%s\"\n" + " ]\n" + "}", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling"); + } return jsonString; // Return the allocated JSON string } else @@ -261,26 +295,53 @@ char* testRestYamlCallback(const char *restApi, const char* requestType, ut_kvp_ } // Construct the YAML string using sprintf - sprintf(yamlString, - "---\n" - "name: John Doe\n" - "age: %d\n" - "email: %s\n" - "isMarried: %s\n" - "children:\n" - " - name: %s\n" - " age: %d\n" - " - name: %s\n" - " age: %d\n" - "hobbies:\n" - " - %s\n" - " - %s\n" - " - %s\n", - 30, "johndoe@example.com", "false", - "Alice", 5, - "Bob", 3, - "reading", "cycling", "traveling"); + if (instance != NULL) + { + sprintf(yamlString, + "---\n" + "name: John Doe\n" + "age: %d\n" + "email: %s\n" + "isMarried: %s\n" + "children:\n" + " - name: %s\n" + " age: %d\n" + " - name: %s\n" + " age: %d\n" + "hobbies:\n" + " - %s\n" + " - %s\n" + " - %s\n" + "pData: %s\n", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling", (char *)instance); + UT_LOG("pData = [%s]\n", (char *)instance); + } + else + { + sprintf(yamlString, + "---\n" + "name: John Doe\n" + "age: %d\n" + "email: %s\n" + "isMarried: %s\n" + "children:\n" + " - name: %s\n" + " age: %d\n" + " - name: %s\n" + " age: %d\n" + "hobbies:\n" + " - %s\n" + " - %s\n" + " - %s\n", + 30, "johndoe@example.com", "false", + "Alice", 5, + "Bob", 3, + "reading", "cycling", "traveling"); + } return yamlString; // Return the allocated Yaml string } else diff --git a/tests/websocket-clients/curl-get-filtered-client-json.sh b/tests/websocket-clients/curl-get-filtered-client-json.sh new file mode 100755 index 0000000..09e0a84 --- /dev/null +++ b/tests/websocket-clients/curl-get-filtered-client-json.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callMyFunction?category=X&price_lt=Y" -H "Accept: application/json" diff --git a/tests/websocket-clients/curl-get-filtered-client-yaml.sh b/tests/websocket-clients/curl-get-filtered-client-yaml.sh new file mode 100755 index 0000000..b5bc384 --- /dev/null +++ b/tests/websocket-clients/curl-get-filtered-client-yaml.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callMyFunction?category=X&price_lt=Y" -H "Accept: application/x-yaml" diff --git a/tests/websocket-clients/test_script_for_curl_request.sh b/tests/websocket-clients/test_script_for_curl_request.sh index 8e6882e..d9e3ea7 100755 --- a/tests/websocket-clients/test_script_for_curl_request.sh +++ b/tests/websocket-clients/test_script_for_curl_request.sh @@ -49,7 +49,43 @@ hobbies: ["./curl-push-client-binary.sh"]="" ["./curl-push-client-json.sh"]="" ["./curl-push-client-yaml.sh"]="" -) + ["./curl-get-filtered-client-json.sh"]='{ + "name": "John Doe", + "age": 30, + "email": "johndoe@example.com", + "isMarried": false, + "children": [ + { + "name": "Alice", + "age": 5 + }, + { + "name": "Bob", + "age": 3 + } + ], + "hobbies": [ + "reading", + "cycling", + "traveling" + ], + "pData": "category=X&price_lt=Y" +}' + ["./curl-get-filtered-client-yaml.sh"]='--- +name: John Doe +age: 30 +email: johndoe@example.com +isMarried: false +children: +- name: Alice + age: 5 +- name: Bob + age: 3 +hobbies: +- reading +- cycling +- traveling +pData: category=X&price_lt=Y') # Loop through tests and validate output for script in "${!tests[@]}"; do From 1f31e44aa782f112601e59b412a9ee86b8c9647e Mon Sep 17 00:00:00 2001 From: kanjoe24 <165808281+kanjoe24@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:06:53 +0000 Subject: [PATCH 9/9] Rename gh #66 : Renaming the test scripts --- tests/Makefile | 2 +- .../GET-request-filtered-json.sh} | 0 .../GET-request-filtered-yaml.sh} | 0 .../GET-request-json-incorrect.sh} | 0 .../GET-request-json.sh} | 0 .../GET-request-no-header.sh} | 0 .../GET-request-yaml-incorrect.sh} | 0 .../GET-request-yaml.sh} | 0 .../POST-request-binary.sh} | 0 .../POST-request-json.sh} | 0 .../POST-request-yaml.sh} | 0 .../example.json | 0 .../example.yaml | 0 .../get_example.json | 0 .../get_example.yaml | 0 .../python-client-send-json.py | 0 .../python-client-send-yaml.py | 0 .../simple_websocket.py | 0 .../test_script_for_curl_request.sh | 20 +++++++++---------- 19 files changed, 11 insertions(+), 11 deletions(-) rename tests/{websocket-clients/curl-get-filtered-client-json.sh => rest-api-clients/GET-request-filtered-json.sh} (100%) rename tests/{websocket-clients/curl-get-filtered-client-yaml.sh => rest-api-clients/GET-request-filtered-yaml.sh} (100%) rename tests/{websocket-clients/curl-get-client-json-incorrect.sh => rest-api-clients/GET-request-json-incorrect.sh} (100%) rename tests/{websocket-clients/curl-get-client-json.sh => rest-api-clients/GET-request-json.sh} (100%) rename tests/{websocket-clients/curl-get-client-no-header.sh => rest-api-clients/GET-request-no-header.sh} (100%) rename tests/{websocket-clients/curl-get-client-yaml-incorrect.sh => rest-api-clients/GET-request-yaml-incorrect.sh} (100%) rename tests/{websocket-clients/curl-get-client-yaml.sh => rest-api-clients/GET-request-yaml.sh} (100%) rename tests/{websocket-clients/curl-push-client-binary.sh => rest-api-clients/POST-request-binary.sh} (100%) rename tests/{websocket-clients/curl-push-client-json.sh => rest-api-clients/POST-request-json.sh} (100%) rename tests/{websocket-clients/curl-push-client-yaml.sh => rest-api-clients/POST-request-yaml.sh} (100%) rename tests/{websocket-clients => rest-api-clients}/example.json (100%) rename tests/{websocket-clients => rest-api-clients}/example.yaml (100%) rename tests/{websocket-clients => rest-api-clients}/get_example.json (100%) rename tests/{websocket-clients => rest-api-clients}/get_example.yaml (100%) rename tests/{websocket-clients => rest-api-clients}/python-client-send-json.py (100%) rename tests/{websocket-clients => rest-api-clients}/python-client-send-yaml.py (100%) rename tests/{websocket-clients => rest-api-clients}/simple_websocket.py (100%) rename tests/{websocket-clients => rest-api-clients}/test_script_for_curl_request.sh (79%) diff --git a/tests/Makefile b/tests/Makefile index bfcba10..bb73d87 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -76,7 +76,7 @@ build: make -C ./ut-core test @cp $(LIB_DIR)/lib* ${BIN_DIR} @cp ${ROOT_DIR}/src/*.sh ${BIN_DIR} - @cp ${ROOT_DIR}/websocket-clients/* ${BIN_DIR} + @cp ${ROOT_DIR}/rest-api-clients/* ${BIN_DIR} @$(ECHOE) ${GREEN}Copy Assets to [${BIN_DIR}/assets] ${NC} @mkdir -p ${BIN_DIR}/assets @cp -r ${ROOT_DIR}/src/assets/* ${BIN_DIR}/assets diff --git a/tests/websocket-clients/curl-get-filtered-client-json.sh b/tests/rest-api-clients/GET-request-filtered-json.sh similarity index 100% rename from tests/websocket-clients/curl-get-filtered-client-json.sh rename to tests/rest-api-clients/GET-request-filtered-json.sh diff --git a/tests/websocket-clients/curl-get-filtered-client-yaml.sh b/tests/rest-api-clients/GET-request-filtered-yaml.sh similarity index 100% rename from tests/websocket-clients/curl-get-filtered-client-yaml.sh rename to tests/rest-api-clients/GET-request-filtered-yaml.sh diff --git a/tests/websocket-clients/curl-get-client-json-incorrect.sh b/tests/rest-api-clients/GET-request-json-incorrect.sh similarity index 100% rename from tests/websocket-clients/curl-get-client-json-incorrect.sh rename to tests/rest-api-clients/GET-request-json-incorrect.sh diff --git a/tests/websocket-clients/curl-get-client-json.sh b/tests/rest-api-clients/GET-request-json.sh similarity index 100% rename from tests/websocket-clients/curl-get-client-json.sh rename to tests/rest-api-clients/GET-request-json.sh diff --git a/tests/websocket-clients/curl-get-client-no-header.sh b/tests/rest-api-clients/GET-request-no-header.sh similarity index 100% rename from tests/websocket-clients/curl-get-client-no-header.sh rename to tests/rest-api-clients/GET-request-no-header.sh diff --git a/tests/websocket-clients/curl-get-client-yaml-incorrect.sh b/tests/rest-api-clients/GET-request-yaml-incorrect.sh similarity index 100% rename from tests/websocket-clients/curl-get-client-yaml-incorrect.sh rename to tests/rest-api-clients/GET-request-yaml-incorrect.sh diff --git a/tests/websocket-clients/curl-get-client-yaml.sh b/tests/rest-api-clients/GET-request-yaml.sh similarity index 100% rename from tests/websocket-clients/curl-get-client-yaml.sh rename to tests/rest-api-clients/GET-request-yaml.sh diff --git a/tests/websocket-clients/curl-push-client-binary.sh b/tests/rest-api-clients/POST-request-binary.sh similarity index 100% rename from tests/websocket-clients/curl-push-client-binary.sh rename to tests/rest-api-clients/POST-request-binary.sh diff --git a/tests/websocket-clients/curl-push-client-json.sh b/tests/rest-api-clients/POST-request-json.sh similarity index 100% rename from tests/websocket-clients/curl-push-client-json.sh rename to tests/rest-api-clients/POST-request-json.sh diff --git a/tests/websocket-clients/curl-push-client-yaml.sh b/tests/rest-api-clients/POST-request-yaml.sh similarity index 100% rename from tests/websocket-clients/curl-push-client-yaml.sh rename to tests/rest-api-clients/POST-request-yaml.sh diff --git a/tests/websocket-clients/example.json b/tests/rest-api-clients/example.json similarity index 100% rename from tests/websocket-clients/example.json rename to tests/rest-api-clients/example.json diff --git a/tests/websocket-clients/example.yaml b/tests/rest-api-clients/example.yaml similarity index 100% rename from tests/websocket-clients/example.yaml rename to tests/rest-api-clients/example.yaml diff --git a/tests/websocket-clients/get_example.json b/tests/rest-api-clients/get_example.json similarity index 100% rename from tests/websocket-clients/get_example.json rename to tests/rest-api-clients/get_example.json diff --git a/tests/websocket-clients/get_example.yaml b/tests/rest-api-clients/get_example.yaml similarity index 100% rename from tests/websocket-clients/get_example.yaml rename to tests/rest-api-clients/get_example.yaml diff --git a/tests/websocket-clients/python-client-send-json.py b/tests/rest-api-clients/python-client-send-json.py similarity index 100% rename from tests/websocket-clients/python-client-send-json.py rename to tests/rest-api-clients/python-client-send-json.py diff --git a/tests/websocket-clients/python-client-send-yaml.py b/tests/rest-api-clients/python-client-send-yaml.py similarity index 100% rename from tests/websocket-clients/python-client-send-yaml.py rename to tests/rest-api-clients/python-client-send-yaml.py diff --git a/tests/websocket-clients/simple_websocket.py b/tests/rest-api-clients/simple_websocket.py similarity index 100% rename from tests/websocket-clients/simple_websocket.py rename to tests/rest-api-clients/simple_websocket.py diff --git a/tests/websocket-clients/test_script_for_curl_request.sh b/tests/rest-api-clients/test_script_for_curl_request.sh similarity index 79% rename from tests/websocket-clients/test_script_for_curl_request.sh rename to tests/rest-api-clients/test_script_for_curl_request.sh index d9e3ea7..e837135 100755 --- a/tests/websocket-clients/test_script_for_curl_request.sh +++ b/tests/rest-api-clients/test_script_for_curl_request.sh @@ -8,8 +8,8 @@ NC='\033[0m' # No color # Define test scripts and expected results declare -A tests=( - ["./curl-get-client-yaml-incorrect.sh"]="error: Internal Server Error" - ["./curl-get-client-yaml.sh"]="--- + ["./GET-request-yaml-incorrect.sh"]="error: Internal Server Error" + ["./GET-request-yaml.sh"]="--- name: John Doe age: 30 email: johndoe@example.com @@ -23,8 +23,8 @@ hobbies: - reading - cycling - traveling" - ["./curl-get-client-json-incorrect.sh"]='{"error": "Internal Server Error"}' - ["./curl-get-client-json.sh"]='{ + ["./GET-request-json-incorrect.sh"]='{"error": "Internal Server Error"}' + ["./GET-request-json.sh"]='{ "name": "John Doe", "age": 30, "email": "johndoe@example.com", @@ -45,11 +45,11 @@ hobbies: "traveling" ] }' - ["./curl-get-client-no-header.sh"]='{"error": "Missing or Invalid Accept header"}' - ["./curl-push-client-binary.sh"]="" - ["./curl-push-client-json.sh"]="" - ["./curl-push-client-yaml.sh"]="" - ["./curl-get-filtered-client-json.sh"]='{ + ["./GET-request-no-header.sh"]='{"error": "Missing or Invalid Accept header"}' + ["./POST-request-binary.sh"]="" + ["./POST-request-json.sh"]="" + ["./POST-request-yaml.sh"]="" + ["./GET-request-filtered-json.sh"]='{ "name": "John Doe", "age": 30, "email": "johndoe@example.com", @@ -71,7 +71,7 @@ hobbies: ], "pData": "category=X&price_lt=Y" }' - ["./curl-get-filtered-client-yaml.sh"]='--- + ["./GET-request-filtered-yaml.sh"]='--- name: John Doe age: 30 email: johndoe@example.com