diff --git a/.vscode/settings.json b/.vscode/settings.json index c7554ad..7a92065 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -64,7 +64,15 @@ "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", + "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 bdb5804..88e3c81 100644 --- a/include/ut_control_plane.h +++ b/include/ut_control_plane.h @@ -47,9 +47,27 @@ typedef struct typedef void ut_controlPlane_instance_t; /*!< Handle to a control plane instance */ +/**** 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 HTTP requests to a specific REST API endpoint. + * + * 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 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. + * + * @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)(const char *restAPI, const char *httpRequestType, ut_kvp_instance_t *pData, void *userData); + /** * @brief Initializes a control plane instance. * @param monitorPort - Port number to monitor for incoming messages. @@ -58,6 +76,7 @@ typedef void (*ut_control_callback_t)( char *key, ut_kvp_instance_t *instance, v ut_controlPlane_instance_t* UT_ControlPlane_Init( uint32_t monitorPort ); /** + * **** 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. @@ -74,6 +93,39 @@ ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPl ut_control_callback_t callbackFunction, void *userData); +/** + * @brief Registers a callback for a REST API endpoint (GET) or POST message key. + * + * 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[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, + const char *httpRequestType, + char *restAPI, ut_control_endpoint_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/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 e682b4d..daa4537 100644 --- a/src/ut_control_plane.c +++ b/src/ut_control_plane.c @@ -34,15 +34,17 @@ #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 { - char key[UT_KVP_MAX_ELEMENT_SIZE]; - ut_control_callback_t pCallback; - void* userData; -}CallbackEntry_t; + char key[UT_KVP_MAX_ELEMENT_SIZE]; + ut_control_endpoint_callback_t pCallback; + void *userData; + char requestType[MAX_REQUEST_SIZE]; +} CallbackEntry_t; typedef enum { @@ -55,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 @@ -86,12 +89,15 @@ 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; }; #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 ) @@ -102,6 +108,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); } @@ -130,6 +137,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++) { @@ -144,34 +152,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_open() - 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.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) @@ -288,26 +294,263 @@ static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void return 0; } #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) +{ + char* response = NULL; + char* kvpData = NULL; + ut_kvp_instance_t *pkvpInstance = NULL; + ut_kvp_status_t status; + + for (uint32_t i = 0; i < pInternal->callback_entry_index; i++) + { + CallbackEntry_t entry = pInternal->callbackEntryList[i]; + + if (compareStrings(entry.key, key) == 0) + { + 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 + status = ut_kvp_openMemory(pkvpInstance, kvpData, strlen(kvpData)); + if (status != UT_KVP_STATUS_SUCCESS) + { + UT_CONTROL_PLANE_ERROR("ut_kvp_openMemory() - Read Failure\n"); + ut_kvp_destroyInstance(pkvpInstance); + return NULL; + } + 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; +} + +// 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; + int result; + + if (strncmp(accept_header, "application/x-yaml", 18) == 0) + { + response_format = "application/x-yaml"; + error_response = yaml_msg; + } + + result = send_error_response(wsi, status, response_format, error_response) < 0 ? -1 : -1; + return result; +} + +// 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"); + } + + 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; - 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; + 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: { + case LWS_CALLBACK_HTTP: + { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); - char *requested_uri = (char *)in; - if (strcmp(requested_uri, "/api/postKVP") == 0) - { + 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)) { + 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; + return 0; // Let the body handling process continue } + + // Handle GET request for /api/ + + // Validate Accept header + if (validate_accept_header(wsi, accept_header, sizeof(accept_header)) < 0) + { + return -1; + } + + // Validate URI + if (strncmp(requested_uri, "/api/", 5) != 0) + { + UT_CONTROL_PLANE_ERROR("Invalid URI: %s\n", requested_uri); + 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) + { + result = send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Missing key in URI\"}", + "error: Missing key in URI\n"); + 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) + { + result = send_error(wsi, HTTP_STATUS_BAD_REQUEST, accept_header, + "{\"error\": \"Internal Server Error\"}", + "error: Internal Server Error\n"); + return result; + } + + // 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; + } + + if (lws_finalize_http_header(wsi, &p, end) < 0) + { + free(response); + return -1; + } + + if (lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0) + { + free(response); + 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: { UT_CONTROL_PLANE_DEBUG("LWS_CALLBACK_HTTP\n"); @@ -322,6 +565,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; } } @@ -345,18 +589,22 @@ 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\"}"; // lws_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP); return 1; // HTTP request handled } + break; } default: break; - } - return 0; + } + return 0; } #endif @@ -379,7 +627,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 } @@ -489,39 +737,50 @@ void UT_ControlPlane_Stop( ut_controlPlane_instance_t *pInstance ) } ut_control_plane_status_t UT_ControlPlane_RegisterCallbackOnMessage(ut_controlPlane_instance_t *pInstance, char *key, ut_control_callback_t callbackFunction, void *userData) +{ + 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, 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; - 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 (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 ) - { + 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); + 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->callback_entry_index++; 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/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/rest-api-clients/GET-request-filtered-json.sh b/tests/rest-api-clients/GET-request-filtered-json.sh new file mode 100755 index 0000000..09e0a84 --- /dev/null +++ b/tests/rest-api-clients/GET-request-filtered-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/rest-api-clients/GET-request-filtered-yaml.sh b/tests/rest-api-clients/GET-request-filtered-yaml.sh new file mode 100755 index 0000000..b5bc384 --- /dev/null +++ b/tests/rest-api-clients/GET-request-filtered-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/rest-api-clients/GET-request-json-incorrect.sh b/tests/rest-api-clients/GET-request-json-incorrect.sh new file mode 100755 index 0000000..a6448b0 --- /dev/null +++ b/tests/rest-api-clients/GET-request-json-incorrect.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callMyIncorrectFunction" -H "Accept: application/json" diff --git a/tests/rest-api-clients/GET-request-json.sh b/tests/rest-api-clients/GET-request-json.sh new file mode 100755 index 0000000..d016b91 --- /dev/null +++ b/tests/rest-api-clients/GET-request-json.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callMyFunction2" -H "Accept: application/json" diff --git a/tests/rest-api-clients/GET-request-no-header.sh b/tests/rest-api-clients/GET-request-no-header.sh new file mode 100755 index 0000000..dd40113 --- /dev/null +++ b/tests/rest-api-clients/GET-request-no-header.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callNoHeaderMyFunction" diff --git a/tests/rest-api-clients/GET-request-yaml-incorrect.sh b/tests/rest-api-clients/GET-request-yaml-incorrect.sh new file mode 100755 index 0000000..136135f --- /dev/null +++ b/tests/rest-api-clients/GET-request-yaml-incorrect.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callIncorrectYaml" -H "Accept: application/x-yaml" diff --git a/tests/rest-api-clients/GET-request-yaml.sh b/tests/rest-api-clients/GET-request-yaml.sh new file mode 100755 index 0000000..c121f83 --- /dev/null +++ b/tests/rest-api-clients/GET-request-yaml.sh @@ -0,0 +1 @@ +curl -X GET "http://localhost:8080/api/v1/callMyFunction" -H "Accept: application/x-yaml" diff --git a/tests/rest-api-clients/POST-request-binary.sh b/tests/rest-api-clients/POST-request-binary.sh new file mode 100755 index 0000000..93d713a --- /dev/null +++ b/tests/rest-api-clients/POST-request-binary.sh @@ -0,0 +1,2 @@ +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-client-json.sh b/tests/rest-api-clients/POST-request-json.sh similarity index 60% rename from tests/websocket-clients/curl-client-json.sh rename to tests/rest-api-clients/POST-request-json.sh index d7ff4a2..281a539 100755 --- a/tests/websocket-clients/curl-client-json.sh +++ b/tests/rest-api-clients/POST-request-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/postJson \ No newline at end of file diff --git a/tests/websocket-clients/curl-client-yaml.sh b/tests/rest-api-clients/POST-request-yaml.sh similarity index 55% rename from tests/websocket-clients/curl-client-yaml.sh rename to tests/rest-api-clients/POST-request-yaml.sh index b93570d..54a9141 100755 --- a/tests/websocket-clients/curl-client-yaml.sh +++ b/tests/rest-api-clients/POST-request-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/postYaml 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/rest-api-clients/get_example.json b/tests/rest-api-clients/get_example.json new file mode 100644 index 0000000..5e76e8f --- /dev/null +++ b/tests/rest-api-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/rest-api-clients/get_example.yaml b/tests/rest-api-clients/get_example.yaml new file mode 100644 index 0000000..5c92927 --- /dev/null +++ b/tests/rest-api-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/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/rest-api-clients/test_script_for_curl_request.sh b/tests/rest-api-clients/test_script_for_curl_request.sh new file mode 100755 index 0000000..e837135 --- /dev/null +++ b/tests/rest-api-clients/test_script_for_curl_request.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +# Define color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No color + +# Define test scripts and expected results +declare -A tests=( + ["./GET-request-yaml-incorrect.sh"]="error: Internal Server Error" + ["./GET-request-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" + ["./GET-request-json-incorrect.sh"]='{"error": "Internal Server Error"}' + ["./GET-request-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" + ] +}' + ["./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", + "isMarried": false, + "children": [ + { + "name": "Alice", + "age": 5 + }, + { + "name": "Bob", + "age": 3 + } + ], + "hobbies": [ + "reading", + "cycling", + "traveling" + ], + "pData": "category=X&price_lt=Y" +}' + ["./GET-request-filtered-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 + echo "Running: $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 -e "${YELLOW}Got:${NC}" + echo "$output" + fi + echo "---------------------------------" +done diff --git a/tests/src/ut_test_control_plane.c b/tests/src/ut_test_control_plane.c index 93653b6..b2019fb 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; @@ -51,7 +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* 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,37 +130,54 @@ static void test_ut_control_l1_regsiterCallback() 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_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); + status = UT_ControlPlane_RegisterEndPointCallback(pInstance, "GET", NULL, &testRestJSONCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_PARAM); + + 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, "GET", "/v1/callMyFunction2", &testRestJSONCallback, userData); + UT_ASSERT_EQUAL(status, UT_CONTROL_PLANE_STATUS_INVALID_HANDLE); + + 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_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, 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_RegisterCallbackOnMessage(pInstance, "test/yamlData", &testYAMLCallback, 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 @@ -167,54 +187,182 @@ static void test_ut_control_l1_regsiterCallback() } /* 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 + 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 } - - 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 + 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"); - if(data != NULL) - { - printf("Original Json file\n%s", data); + } + return yamlString; // Return the allocated Yaml string } + else + { + char *kvpData; + UT_LOG("**************testRestYamlCallback POST is called****************\n"); + kvpData = ut_kvp_getData(instance); + + if (kvpData != NULL) + { + // Print the emitted KVP string + printf("%s\n", kvpData); + + // Free the emitted KVP string + free(kvpData); + } - //UT_ASSERT_STRING_EQUAL(kvpData, data); - gMessageRecievedJSON = true; + // UT_ASSERT_STRING_EQUAL(kvpData, data); + gMessageRecievedYAML = true; + return NULL; + } } static void UT_ControlPlane_Sigint_Handler(int sig) @@ -233,9 +381,11 @@ static void test_ut_control_performInit( void ) static void test_ut_control_performStart() { + UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testRestYamlCallback - Negative\n"); + UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "postBinaryYaml", (ut_control_callback_t)&testRestYamlCallback, NULL); - UT_LOG("UT_ControlPlane_RegisterCallbackOnMessage() client testYAMLCallback - Negative\n"); - UT_ControlPlane_RegisterCallbackOnMessage(gInstance, "test/yamlData", &testYAMLCallback, 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) { @@ -243,12 +393,16 @@ 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); + + 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 testRestJSONCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "GET", "/v1/callMyFunction2", &testRestJSONCallback, NULL); + UT_ControlPlane_Start(gInstance); /* This should still work after start */ @@ -259,11 +413,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, (void *)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 testRestYamlCallback - Positive \n"); + UT_ControlPlane_RegisterEndPointCallback(gInstance, "GET", "/v1/callMyFunction", &testRestYamlCallback, NULL); } void run_client_function() @@ -276,7 +433,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 `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 @@ -346,7 +503,7 @@ 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_regsiterCallback); UT_add_test(gpAssertSuite1, "ut-cp websocket service", test_ut_control_l1_testStartStop); /* L2 - ut_control Module tests */ 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-client-binary.sh b/tests/websocket-clients/curl-client-binary.sh deleted file mode 100755 index a380117..0000000 --- a/tests/websocket-clients/curl-client-binary.sh +++ /dev/null @@ -1,2 +0,0 @@ -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