diff --git a/ci/run_utest.sh b/ci/run_utest.sh index 1b916e06..fc2fb2c2 100755 --- a/ci/run_utest.sh +++ b/ci/run_utest.sh @@ -1,4 +1,23 @@ #!/bin/bash +############################################################################### +print_info() { + echo " + Run the unit test suite or parts of it. Default is to run all unit + tests for the Debug build. + + Usage: ${0} [build type] [--test-regex|-R ] [-h|--help] + + build type: usually Debug or Release but can be any other build type + --test-regex|-R: execute all tests matching the pattern + -h|--help: print this help + + Examples: + ${0} Release # run all unit test on Release build + ${0} Release -R elosRpn # run all unit test containing elosRpn in + the name for the Release build. + " +} +############################################################################### set -e -u -o pipefail CMD_PATH="$(realpath "$(dirname "$0")")" @@ -12,8 +31,13 @@ while [ $# -gt 0 ]; do TESTS_REGEX="--tests-regex ${2}" shift ;; + -h|--help) + print_info + exit 0 ;; -*) - echo "error: unknown option: $1"; exit 1 ;; + echo "error: unknown option: $1" + print_info + exit 1 ;; *) PARAM="$PARAM ${1}" ;; esac diff --git a/cmake/project.cmake b/cmake/project.cmake index 40329bb3..80c4e1e2 100644 --- a/cmake/project.cmake +++ b/cmake/project.cmake @@ -1,5 +1,5 @@ # SPDX-License-Identifier: MIT -set(ELOS_VERSION 0.64.1) +set(ELOS_VERSION 0.64.2) # Attention: Aside from the version, as many things as possible in this file # should be put into functions, as this solves potential issues with commands diff --git a/src/demos/elosc.c b/src/demos/elosc.c index f975f6e4..a0a9fb9d 100644 --- a/src/demos/elosc.c +++ b/src/demos/elosc.c @@ -338,9 +338,11 @@ static safuResultE_t _commandLogFindEvent(elosSession_t *session, elosConfig_t * elosEventVector_t *eventVector = NULL; int retVal; - retVal = elosLogFindEvent(session, config->commandArgs, &eventVector); + struct timespec newest = {0}; + struct timespec oldest = {0}; + retVal = elosFindEvents(session, config->commandArgs, &newest, &oldest, &eventVector); if (retVal < 0) { - fprintf(stderr, "log event find failed!\n"); + fprintf(stderr, "event find failed!\n"); } else if (eventVector == NULL) { printf("No matching events returned\n"); result = SAFU_RESULT_OK; diff --git a/src/libelos/private/libelos.c b/src/libelos/private/libelos.c index e60bb2fb..ed16f642 100644 --- a/src/libelos/private/libelos.c +++ b/src/libelos/private/libelos.c @@ -1,22 +1,26 @@ // SPDX-License-Identifier: MIT -#include #include -#include +#include +#include +#include +#include #include #include +#include + +#include "elos/event/event_types.h" +#include "elos/event/event_vector.h" #define _DEFAULT_SOURCE 1 -#include -#include -#include #include +#include +#include #include #include #include #include #include -#include #include #include @@ -25,9 +29,6 @@ #include "elos/libelos/libelos.h" #include "libelos_communication.h" #include "libelos_constructor.h" -#include "safu/common.h" -#include "safu/json.h" -#include "safu/log.h" #define VERSION_DATA_LEN 128 @@ -212,57 +213,118 @@ safuResultE_t elosGetVersion(elosSession_t *session, char const **version) { return result; } +// Deprecated safuResultE_t elosLogFindEvent(elosSession_t *session, const char *filterRule, elosEventVector_t **eventVector) { + return elosFindEvents(session, filterRule, &(struct timespec){0}, &(struct timespec){0}, eventVector); +} + +static safuResultE_t _createFindEventRequest(const char *filterRule, struct timespec const *newest, + struct timespec const *oldest, json_object **jRequest) { safuResultE_t result = SAFU_RESULT_FAILED; - bool retBool; - retBool = elosSessionValid(session); - if (retBool == false) { - if (elosLoggingEnabled) safuLogErr("Invalid session"); - } else if ((filterRule == NULL) || (eventVector == NULL)) { - if (elosLoggingEnabled) safuLogErr("Invalid parameter"); + json_object *newJsonRequest = json_object_new_object(); + if (newJsonRequest == NULL) { + if (elosLoggingEnabled) safuLogErr("json_object_new_object failed!"); } else { - json_object *jRequest = NULL; + json_object *jsonAttribute = NULL; + jsonAttribute = safuJsonAddNewString(newJsonRequest, "filter", filterRule); + if (jsonAttribute == NULL) { + if (elosLoggingEnabled) safuLogErr("safuJsonAddNewString failed!"); + } else { + jsonAttribute = safuJsonAddNewTimestamp(newJsonRequest, "newest", newest); + if (jsonAttribute == NULL) { + if (elosLoggingEnabled) safuLogErr("safuJsonAddNewTimestamp failed!"); + } else { + jsonAttribute = safuJsonAddNewTimestamp(newJsonRequest, "oldest", oldest); + if (jsonAttribute == NULL) { + if (elosLoggingEnabled) safuLogErr("safuJsonAddNewTimestamp failed!"); + } + } + } - jRequest = json_object_new_object(); - if (!jRequest) { - if (elosLoggingEnabled) safuLogErr("json_object_new_object failed!"); + if (jsonAttribute == NULL) { + json_object_put(newJsonRequest); } else { - json_object *filterRuleComplete = NULL; + *jRequest = newJsonRequest; + result = SAFU_RESULT_OK; + } + } + + return result; +} + +static safuResultE_t _readFindEventResponse(json_object *jResponse, elosEventVector_t **eventVector, + bool *isTruncated) { + safuResultE_t result = SAFU_RESULT_FAILED; - filterRuleComplete = safuJsonAddNewString(jRequest, "filter", filterRule); - if (!filterRuleComplete) { - if (elosLoggingEnabled) safuLogErr("safuJsonAddNewString failed!"); + json_object *jIsTruncated = safuJsonGetObject(jResponse, "isTruncated", 0); + if (jIsTruncated != NULL && json_object_get_type(jIsTruncated) == json_type_boolean) { + *isTruncated = json_object_get_boolean(jIsTruncated); + } else { + *isTruncated = false; + } + + json_object *eventVecJarr = safuJsonGetArray(jResponse, "eventArray", 0, NULL); + if (!eventVecJarr) { + if (elosLoggingEnabled) safuLogErr("Failed to read event vector json object!"); + } else { + elosEventVector_t *newEventVector = NULL; + + result = elosEventVectorFromJsonArray(eventVecJarr, &newEventVector); + if (result == SAFU_RESULT_FAILED) { + if (elosLoggingEnabled) safuLogErr("Failed to read event vector json object!"); + } else { + if (*eventVector == NULL) { + *eventVector = newEventVector; } else { - uint8_t const messageId = ELOS_MESSAGE_LOG_FIND_EVENT; - json_object *jResponse; - safuResultE_t retResult; + size_t eventCount = safuVecElements(newEventVector); + for (size_t i = 0; i < eventCount; i++) { + elosEventVectorPush(*eventVector, safuVecGet(newEventVector, i)); + } + safuVecFree(newEventVector); + free(newEventVector); + } + result = SAFU_RESULT_OK; + } + } + return result; +} +safuResultE_t elosFindEvents(elosSession_t *session, const char *filterRule, struct timespec const *newest, + struct timespec const *oldest, elosEventVector_t **eventVector) { + safuResultE_t result = SAFU_RESULT_FAILED; + bool retBool; + bool isTruncated = false; + + retBool = elosSessionValid(session); + if (retBool == false) { + if (elosLoggingEnabled) safuLogErr("Invalid session"); + } else if ((filterRule == NULL) || (eventVector == NULL) || (newest == NULL) || (oldest == NULL)) { + if (elosLoggingEnabled) safuLogErr("Invalid parameter"); + } else { + struct timespec currentOldest = *oldest; + do { + json_object *jRequest = NULL; + result = _createFindEventRequest(filterRule, newest, ¤tOldest, &jRequest); + if (result == SAFU_RESULT_OK) { if (elosLoggingEnabled) safuLogDebugF("will send filter rule: %s", filterRule); - retResult = elosSendAndReceiveJsonMessage(session, messageId, jRequest, &jResponse); - if (retResult != SAFU_RESULT_OK) { + + json_object *jResponse = NULL; + result = elosSendAndReceiveJsonMessage(session, ELOS_MESSAGE_LOG_FIND_EVENT, jRequest, &jResponse); + if (result != SAFU_RESULT_OK) { if (elosLoggingEnabled) safuLogErr("Communication with elosd failed!"); } else { - json_object *eventVecJarr = safuJsonGetArray(jResponse, "eventArray", 0, NULL); - if (!eventVecJarr) { - if (elosLoggingEnabled) safuLogErr("Failed to read event vector json object!"); - } else { - elosEventVector_t *newEventVector = NULL; - - retResult = elosEventVectorFromJsonArray(eventVecJarr, &newEventVector); - if (retResult == SAFU_RESULT_FAILED) { - if (elosLoggingEnabled) safuLogErr("Failed to read event vector json object!"); - } else { - *eventVector = newEventVector; - result = SAFU_RESULT_OK; - } + result = _readFindEventResponse(jResponse, eventVector, &isTruncated); + if (result == SAFU_RESULT_OK && isTruncated) { + elosEvent_t *lastEvent = safuVecGetLast(*eventVector); + currentOldest = lastEvent->date; } json_object_put(jResponse); } - } - json_object_put(jRequest); - } + json_object_put(jRequest); + } + } while (isTruncated); } return result; diff --git a/src/libelos/public/elos/libelos/libelos.h b/src/libelos/public/elos/libelos/libelos.h index 3098d771..f66384fd 100644 --- a/src/libelos/public/elos/libelos/libelos.h +++ b/src/libelos/public/elos/libelos/libelos.h @@ -157,6 +157,9 @@ safuResultE_t elosEventQueueRead(elosSession_t *session, elosEventQueueId_t even * - In case no events are in the log, the vector parameter won't be changed. * - The memory of the event vector will be allocated by the library * and must be freed afterwards with elosEventVectorDelete(). + * + * Warning: Deprecated and can be removed without further notice. Use `elosFindEvents` instead. + * * Input: * - **session**: session data structure * - **filterRule**: filter rule for entry selection @@ -167,6 +170,30 @@ safuResultE_t elosEventQueueRead(elosSession_t *session, elosEventQueueId_t even ******************************************************************/ safuResultE_t elosLogFindEvent(elosSession_t *session, const char *filterRule, elosEventVector_t **eventVector); +/******************************************************************* + * Function: elosFindEvents + *------------------------------------------------------------------ + * Description: + * Fetches all logged events based on the used filter (e.g. based on payload or other data). + * + * - In case no events are in the log, the vector parameter won't be changed. + * - The memory of the event vector will be allocated by the library + * and must be freed afterwards with elosEventVectorDelete(). + * + * + * Input: + * - **session**: session data structure + * - **filterRule**: filter rule for entry selection + * - **newest**: time of the earliest event to look for + * - **oldest**: time of the oldest event to look for + * Output: + * - **vector**: list of event structs + * Returns: + * - `SAFU_RESULT_OK` for success or `SAFU_RESULT_FAILED` on failure + ******************************************************************/ +safuResultE_t elosFindEvents(elosSession_t *session, const char *filterRule, struct timespec const *newest, + struct timespec const *oldest, elosEventVector_t **eventVector); + /******************************************************************* * Function: elosSessionValid *------------------------------------------------------------------ diff --git a/test/integration/tests/clients/elosc/find_event_invalid_filter.robot b/test/integration/tests/clients/elosc/find_event_invalid_filter.robot index 183d4c40..fff065aa 100644 --- a/test/integration/tests/clients/elosc/find_event_invalid_filter.robot +++ b/test/integration/tests/clients/elosc/find_event_invalid_filter.robot @@ -20,7 +20,7 @@ Suite Teardown Close All Connections @{MESSAGES} {"messageCode": 4,"payload":"testEventFiltering"} ... {"messageCode": 40,"payload":"testEventFiltering"} ... {"messageCode": 400,"payload":"testEventFiltering"} -${SEARCH_STRING} "log event find failed" +${SEARCH_STRING} "event find failed" @{PUBLISH_LOG} @{EMPTY} diff --git a/test/utest/libelos/CMakeLists.txt b/test/utest/libelos/CMakeLists.txt index 9f678621..4b8afd21 100644 --- a/test/utest/libelos/CMakeLists.txt +++ b/test/utest/libelos/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(elosEventQueueRead) add_subdirectory(elosEventSubscribe) add_subdirectory(elosEventUnsubscribe) add_subdirectory(elosLogFindEvent) +add_subdirectory(elosFindEvents) add_subdirectory(elosSessionValid) add_subdirectory(private) diff --git a/test/utest/libelos/elosFindEvents/CMakeLists.txt b/test/utest/libelos/elosFindEvents/CMakeLists.txt new file mode 100644 index 00000000..7eff4200 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +find_package(safu 0.56.2 REQUIRED) +find_package(cmocka_mocks 0.54.2 REQUIRED) + +create_unit_test( + NAME + test_libelos_elosFindEvents_utest + SOURCES + case_err_invalid_parameter.c + case_exterr_verify_session.c + case_exterr_new_object.c + case_exterr_add_new_string.c + case_exterr_add_new_timestamp.c + case_exterr_comm_failed.c + case_exterr_vector_from_json_arr.c + case_success.c + case_success_truncated.c + elosFindEvents_utest.c + LIBRARIES + mock_elos_event_static + mock_libelos_static + cmocka_mocks::mock_jsonc + safu::mock_safu +) diff --git a/test/utest/libelos/elosFindEvents/case_err_invalid_parameter.c b/test/utest/libelos/elosFindEvents/case_err_invalid_parameter.c new file mode 100644 index 00000000..15d7dd32 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_err_invalid_parameter.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT + +#include "elosFindEvents_utest.h" + +int elosTestElosFindEventsErrInvalidParameterSetup(UNUSED void **state) { + return 0; +} + +int elosTestElosFindEventsErrInvalidParameterTeardown(UNUSED void **state) { + return 0; +} + +void elosTestElosFindEventsErrInvalidParameter(UNUSED void **state) { + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when any of the parameters is null"); + + elosSession_t session = {.connected = true}; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + elosEventVector_t *eventVector = NULL; + safuResultE_t result = SAFU_RESULT_FAILED; + + PARAM("'session' is NULL"); + result = elosFindEvents(NULL, filterRule, &newest, &oldest, &eventVector); + assert_int_equal(result, SAFU_RESULT_FAILED); + + PARAM("'filterRule' is NULL"); + result = elosFindEvents(&session, NULL, &newest, &oldest, &eventVector); + assert_int_equal(result, SAFU_RESULT_FAILED); + + PARAM("'newest' is NULL"); + result = elosFindEvents(&session, filterRule, NULL, &oldest, &eventVector); + assert_int_equal(result, SAFU_RESULT_FAILED); + PARAM("'oldest' is NULL"); + result = elosFindEvents(&session, filterRule, &newest, NULL, &eventVector); + assert_int_equal(result, SAFU_RESULT_FAILED); + PARAM("'eventVector' is NULL"); + result = elosFindEvents(&session, filterRule, &newest, &oldest, NULL); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_add_new_string.c b/test/utest/libelos/elosFindEvents/case_exterr_add_new_string.c new file mode 100644 index 00000000..ff3ed206 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_add_new_string.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT + +#include + +#include "elosFindEvents_utest.h" + +int elosTestElosFindEventsExtErrAddNewStringSetup(void **state) { + static elosUteststateT_t testState = {0}; + + *state = &testState; + elosFindEventsUtestCreateSession(state); + return 0; +} + +int elosTestElosFindEventsExtErrAddNewStringTeardown(void **state) { + elosFindEventsUtestFreeSession(state); + return 0; +} + +void elosTestElosFindEventsExtErrAddNewString(void **state) { + elosUteststateT_t *testState = *state; + elosSession_t *session = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + elosEventVector_t *vector = NULL; + safuResultE_t result; + + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when safuJsonAddNewString returns null"); + + session->fd = VALID_SESSION_FD; + session->connected = true; + + expect_not_value(__wrap_safuJsonAddNewString, jobj, NULL); + expect_string(__wrap_safuJsonAddNewString, name, "filter"); + expect_string(__wrap_safuJsonAddNewString, val, filterRule); + will_return(__wrap_safuJsonAddNewString, NULL); + MOCK_FUNC_AFTER_CALL(safuJsonAddNewString, 0); + + result = elosFindEvents(session, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_add_new_timestamp.c b/test/utest/libelos/elosFindEvents/case_exterr_add_new_timestamp.c new file mode 100644 index 00000000..1402c88a --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_add_new_timestamp.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +#include "elosFindEvents_utest.h" + +int elosTestElosFindEventsExtErrAddNewTimestampSetup(void **state) { + static elosUteststateT_t testState = {0}; + + *state = &testState; + elosFindEventsUtestCreateSession(state); + return 0; +} + +int elosTestElosFindEventsExtErrAddNewTimestampTeardown(void **state) { + elosFindEventsUtestFreeSession(state); + return 0; +} + +void elosTestElosFindEventsExtErrAddNewTimestamp(void **state) { + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when safuJsonAddNewTimestamp returns null"); + + elosUteststateT_t *testState = *state; + elosSession_t *session = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + elosEventVector_t *vector = NULL; + + expect_not_value(__wrap_safuJsonAddNewTimestamp, jobj, NULL); + expect_string(__wrap_safuJsonAddNewTimestamp, name, "newest"); + expect_memory(__wrap_safuJsonAddNewTimestamp, timestamp, &newest, sizeof(newest)); + will_return(__wrap_safuJsonAddNewTimestamp, NULL); + MOCK_FUNC_AFTER_CALL(safuJsonAddNewTimestamp, 0); + + safuResultE_t result = elosFindEvents(session, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); + + expect_not_value(__wrap_safuJsonAddNewTimestamp, jobj, NULL); + expect_string(__wrap_safuJsonAddNewTimestamp, name, "oldest"); + expect_memory(__wrap_safuJsonAddNewTimestamp, timestamp, &oldest, sizeof(oldest)); + will_return(__wrap_safuJsonAddNewTimestamp, NULL); + MOCK_FUNC_AFTER_CALL(safuJsonAddNewTimestamp, 1); + + result = elosFindEvents(session, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_comm_failed.c b/test/utest/libelos/elosFindEvents/case_exterr_comm_failed.c new file mode 100644 index 00000000..ada18e3e --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_comm_failed.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +#include "elosFindEvents_utest.h" +#include "mock_libelos_communication.h" + +#define RESPONSE_CHUNKS_COUNT 1 + +int elosTestElosFindEventsExtErrCommunicationSetup(void **state) { + static elosUteststateT_t testState = {0}; + *state = &testState; + elosFindEventsUtestCreateSession(state); + testState.expectedJsonRequest = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + testState.expectedJsonResponse = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + + assert_non_null_msg(testState.expectedJsonRequest, "safuAllocMem failed"); + assert_non_null_msg(testState.expectedJsonResponse, "safuAllocMem failed"); + return 0; +} + +int elosTestElosFindEventsExtErrCommunicationTeardown(void **state) { + elosUteststateT_t *testState = *state; + elosFindEventsUtestFreeSession(state); + elosCleanupMockSendAndReceiveJsonMessage(testState); + return 0; +} + +void elosTestElosFindEventsExtErrCommunication(void **state) { + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when elosSendAndReceiveJsonMessage failed"); + + elosUteststateT_t *testState = *state; + + const char *findEventsRequest = + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [0,0]\ + }"; + testState->expectedJsonRequest[0] = json_tokener_parse(findEventsRequest); + assert_non_null_msg(testState->expectedJsonRequest[0], "Failed to parse json request"); + testState->expectedJsonResponse[0] = NULL; + elosMockSendAndReceiveJsonMessage(testState, RESPONSE_CHUNKS_COUNT, SAFU_RESULT_FAILED); + + elosSession_t *mockSession = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + elosEventVector_t *vector = NULL; + safuResultE_t result; + + result = elosFindEvents(mockSession, filterRule, &newest, &oldest, &vector); + + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_new_object.c b/test/utest/libelos/elosFindEvents/case_exterr_new_object.c new file mode 100644 index 00000000..a5dda42b --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_new_object.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +#include "elosFindEvents_utest.h" + +int elosTestElosFindEventsExtErrNewObjectSetup(void **state) { + static elosUteststateT_t testState = {0}; + + *state = &testState; + elosFindEventsUtestCreateSession(state); + return 0; +} + +int elosTestElosFindEventsExtErrNewObjectTeardown(void **state) { + elosFindEventsUtestFreeSession(state); + return 0; +} + +void elosTestElosFindEventsExtErrNewObject(void **state) { + elosUteststateT_t *testState = *state; + elosSession_t *session = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + elosEventVector_t *vector = NULL; + safuResultE_t result; + + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when json_object_new_object returns null"); + + session->fd = VALID_SESSION_FD; + session->connected = true; + + will_return(__wrap_json_object_new_object, NULL); + MOCK_FUNC_AFTER_CALL(json_object_new_object, 0); + + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + result = elosFindEvents(session, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_vector_from_json_arr.c b/test/utest/libelos/elosFindEvents/case_exterr_vector_from_json_arr.c new file mode 100644 index 00000000..68a45c8f --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_vector_from_json_arr.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT + +#include + +#include "elosFindEvents_utest.h" +#include "mock_event_vector.h" +#include "mock_libelos_communication.h" + +#define RESPONSE_CHUNKS_COUNT 1 + +int elosTestElosFindEventsExtErrVectorFromJsonArrSetup(void **state) { + static elosUteststateT_t testState = {0}; + *state = &testState; + elosFindEventsUtestCreateSession(state); + testState.expectedJsonRequest = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + testState.expectedJsonResponse = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + + assert_non_null_msg(testState.expectedJsonRequest, "safuAllocMem failed"); + assert_non_null_msg(testState.expectedJsonResponse, "safuAllocMem failed"); + + return 0; +} + +int elosTestElosFindEventsExtErrVectorFromJsonArrTeardown(void **state) { + elosUteststateT_t *testState = *state; + elosFindEventsUtestFreeSession(state); + elosCleanupMockSendAndReceiveJsonMessage(testState); + return 0; +} + +void elosTestElosFindEventsExtErrVectorFromJsonArr(void **state) { + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when elosEventVectorFromJsonArray returns an empty event vector"); + + elosUteststateT_t *testState = *state; + const char *findEventsRequest = + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [0,0]\ + }"; + testState->expectedJsonRequest[0] = json_tokener_parse(findEventsRequest); + assert_non_null_msg(testState->expectedJsonRequest[0], "Failed to parse json request"); + + const char *findEventsResponse = + "{\ + \"eventArray\": [\ + {\"messageCode\": 1001,\"payload\": \"Hugo hat Husten\"},\ + {\"messageCode\": 1002,\"payload\": \"Hugo hat Husten\"},\ + {\"messageCode\": 1003,\"payload\": \"Hugo hat Husten\"}\ + ],\ + \"isTruncated\": false\ + }"; + testState->expectedJsonResponse[0] = json_tokener_parse(findEventsResponse); + assert_non_null_msg(testState->expectedJsonResponse[0], "Failed to parse json response"); + + elosMockSendAndReceiveJsonMessage(testState, RESPONSE_CHUNKS_COUNT, SAFU_RESULT_OK); + + MOCK_FUNC_AFTER_CALL(elosEventVectorFromJsonArray, 0); + expect_not_value(elosEventVectorFromJsonArray, jEventArray, NULL); + expect_not_value(elosEventVectorFromJsonArray, eventVector, NULL); + will_set_parameter(elosEventVectorFromJsonArray, eventVector, NULL); + will_return(elosEventVectorFromJsonArray, SAFU_RESULT_FAILED); + + elosSession_t *mockSession = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + elosEventVector_t *vector = NULL; + safuResultE_t result = elosFindEvents(mockSession, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_exterr_verify_session.c b/test/utest/libelos/elosFindEvents/case_exterr_verify_session.c new file mode 100644 index 00000000..3aa1f444 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_exterr_verify_session.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +#include "elosFindEvents_utest.h" + +int elosTestElosFindEventsExtErrVerifySessionSetup(void **state) { + static elosUteststateT_t testState = {0}; + + *state = &testState; + elosFindEventsUtestCreateSession(state); + return 0; +} + +int elosTestElosFindEventsExtErrVerifySessionTeardown(void **state) { + elosFindEventsUtestFreeSession(state); + return 0; +} + +void elosTestElosFindEventsExtErrVerifySession(void **state) { + TEST("elosFindEvents"); + SHOULD("%s", "return SAFU_RESULT_FAILED when _verifySession returns a negative value"); + + elosUteststateT_t *testState = *state; + elosSession_t *session = testState->session; + session->fd = INVALID_SESSION_FD; + session->connected = true; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + elosEventVector_t *vector = NULL; + safuResultE_t result; + + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + result = elosFindEvents(session, filterRule, &newest, &oldest, &vector); + assert_int_equal(result, SAFU_RESULT_FAILED); +} diff --git a/test/utest/libelos/elosFindEvents/case_success.c b/test/utest/libelos/elosFindEvents/case_success.c new file mode 100644 index 00000000..99079240 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_success.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +#include "elosFindEvents_utest.h" +#include "mock_libelos_communication.h" + +#define RESPONSE_CHUNKS_COUNT 1 + +int elosTestElosFindEventsSuccessSetup(void **state) { + static elosUteststateT_t testState = {0}; + *state = &testState; + elosFindEventsUtestCreateSession(state); + testState.expectedJsonRequest = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + testState.expectedJsonResponse = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + + assert_non_null_msg(testState.expectedJsonRequest, "safuAllocMem failed"); + assert_non_null_msg(testState.expectedJsonResponse, "safuAllocMem failed"); + + return 0; +} + +int elosTestElosFindEventsSuccessTeardown(void **state) { + elosUteststateT_t *testState = *state; + elosEventVectorDelete(testState->eventVector); + elosFindEventsUtestFreeSession(state); + elosCleanupMockSendAndReceiveJsonMessage(testState); + return 0; +} + +void elosTestElosFindEventsSuccess(void **state) { + TEST("elosFindEvent"); + SHOULD("%s", "return SAFU_RESULT_OK on fetching an untruncated list of events"); + + elosUteststateT_t *testState = *state; + + const char *findEventsRequest = + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [0,0]\ + }"; + testState->expectedJsonRequest[0] = json_tokener_parse(findEventsRequest); + assert_non_null_msg(testState->expectedJsonRequest[0], "Failed to parse json request"); + + const char *findEventsResponse = + "{\ + \"eventArray\": [\ + {\"messageCode\": 1001,\"payload\": \"Hugo hat Husten\"},\ + {\"messageCode\": 1002,\"payload\": \"Hugo hat Husten\"},\ + {\"messageCode\": 1003,\"payload\": \"Hugo hat Husten\"}\ + ],\ + \"isTruncated\": false\ + }"; + testState->expectedJsonResponse[0] = json_tokener_parse(findEventsResponse); + assert_non_null_msg(testState->expectedJsonResponse[0], "Failed to parse json response"); + + elosMockSendAndReceiveJsonMessage(testState, RESPONSE_CHUNKS_COUNT, SAFU_RESULT_OK); + + elosSession_t *mockSession = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + + safuResultE_t result = elosFindEvents(mockSession, filterRule, &newest, &oldest, &testState->eventVector); + + assert_int_equal(result, SAFU_RESULT_OK); + assert_non_null(testState->eventVector); + assert_int_equal(testState->eventVector->elementCount, 3); + + elosEvent_t *event = NULL; + event = safuVecGet(testState->eventVector, 0); + assert_int_equal(event->messageCode, 1001); + assert_string_equal(event->payload, "Hugo hat Husten"); + + event = safuVecGetLast(testState->eventVector); + assert_int_equal(event->messageCode, 1003); + assert_string_equal(event->payload, "Hugo hat Husten"); +} diff --git a/test/utest/libelos/elosFindEvents/case_success_truncated.c b/test/utest/libelos/elosFindEvents/case_success_truncated.c new file mode 100644 index 00000000..fe2feeea --- /dev/null +++ b/test/utest/libelos/elosFindEvents/case_success_truncated.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +#include "elosFindEvents_utest.h" +#include "mock_libelos_communication.h" + +#define RESPONSE_CHUNKS_COUNT 3 + +int elosTestElosFindEventsSuccessTruncatedSetup(void **state) { + static elosUteststateT_t testState = {0}; + *state = &testState; + elosFindEventsUtestCreateSession(state); + testState.expectedJsonRequest = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + testState.expectedJsonResponse = safuAllocMem(NULL, sizeof(json_object *) * RESPONSE_CHUNKS_COUNT); + + assert_non_null_msg(testState.expectedJsonRequest, "safuAllocMem failed"); + assert_non_null_msg(testState.expectedJsonResponse, "safuAllocMem failed"); + + return 0; +} + +int elosTestElosFindEventsSuccessTruncatedTeardown(void **state) { + elosUteststateT_t *testState = *state; + elosFindEventsUtestFreeSession(state); + elosCleanupMockSendAndReceiveJsonMessage(testState); + elosEventVectorDelete(testState->eventVector); + return 0; +} + +void elosTestElosFindEventsSuccessTruncated(void **state) { + TEST("elosFindEvent"); + SHOULD("%s", "return SAFU_RESULT_OK on fetching a truncated list of events"); + + elosUteststateT_t *testState = *state; + + testState->expectedJsonRequest[0] = json_tokener_parse( + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [0,0]\ + }"); + assert_non_null_msg(testState->expectedJsonRequest[0], "Failed to parse json request"); + + testState->expectedJsonResponse[0] = json_tokener_parse( + "{\ + \"eventArray\": [\ + {\"date\":[1,0], \"messageCode\": 1001,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[2,0],\"messageCode\": 1002,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[3,0],\"messageCode\": 1003,\"payload\": \"Hugo hat Husten\"}\ + ],\ + \"isTruncated\": true\ + }"); + assert_non_null_msg(testState->expectedJsonResponse[0], "Failed to parse json response"); + + testState->expectedJsonRequest[1] = json_tokener_parse( + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [3,0]\ + }"); + assert_non_null_msg(testState->expectedJsonRequest[1], "Failed to parse json request"); + + testState->expectedJsonResponse[1] = json_tokener_parse( + "{\ + \"eventArray\": [\ + {\"date\":[4,0], \"messageCode\": 1001,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[5,0],\"messageCode\": 1002,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[6,0],\"messageCode\": 1003,\"payload\": \"Hugo hat Husten\"}\ + ],\ + \"isTruncated\": true\ + }"); + assert_non_null_msg(testState->expectedJsonResponse[1], "Failed to parse json response"); + + testState->expectedJsonRequest[2] = json_tokener_parse( + "{\ + \"filter\": \".event.name 'sshd' STRCMP\",\ + \"newest\": [0,0],\ + \"oldest\": [6,0]\ + }"); + assert_non_null_msg(testState->expectedJsonRequest[2], "Failed to parse json request"); + + testState->expectedJsonResponse[2] = json_tokener_parse( + "{\ + \"eventArray\": [\ + {\"date\":[7,0], \"messageCode\": 1001,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[8,0],\"messageCode\": 1002,\"payload\": \"Hugo hat Husten\"},\ + {\"date\":[9,0],\"messageCode\": 1003,\"payload\": \"Hugo hat Husten\"}\ + ],\ + \"isTruncated\": false\ + }"); + assert_non_null_msg(testState->expectedJsonResponse[2], "Failed to parse json response"); + elosMockSendAndReceiveJsonMessage(testState, RESPONSE_CHUNKS_COUNT, SAFU_RESULT_OK); + + elosSession_t *mockSession = testState->session; + const char filterRule[] = ".event.name 'sshd' STRCMP"; + struct timespec newest = {.tv_sec = 0, .tv_nsec = 0}; + struct timespec oldest = {.tv_sec = 0, .tv_nsec = 0}; + + safuResultE_t result = elosFindEvents(mockSession, filterRule, &newest, &oldest, &testState->eventVector); + + assert_int_equal(result, SAFU_RESULT_OK); + assert_non_null(testState->eventVector); + assert_int_equal(testState->eventVector->elementCount, 9); + elosEvent_t *event; + event = safuVecGet(testState->eventVector, 0); + assert_int_equal(event->messageCode, 1001); + assert_string_equal(event->payload, "Hugo hat Husten"); + struct timespec lastTimestamp = {.tv_sec = 1, .tv_nsec = 0}; + assert_memory_equal(&event->date, &lastTimestamp, sizeof(struct timespec)); + + event = safuVecGetLast(testState->eventVector); + assert_int_equal(event->messageCode, 1003); + assert_string_equal(event->payload, "Hugo hat Husten"); + lastTimestamp = (struct timespec){.tv_sec = 9, .tv_nsec = 0}; + assert_memory_equal(&event->date, &lastTimestamp, sizeof(struct timespec)); +} diff --git a/test/utest/libelos/elosFindEvents/elosFindEvents_utest.c b/test/utest/libelos/elosFindEvents/elosFindEvents_utest.c new file mode 100644 index 00000000..5bddc741 --- /dev/null +++ b/test/utest/libelos/elosFindEvents/elosFindEvents_utest.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#include +#include +#endif + +#include +#include + +#include "elosFindEvents_utest.h" +#include "mock_libelos_communication.h" + +int main() { + const struct CMUnitTest tests[] = { + TEST_CASE(elosTestElosFindEventsErrInvalidParameter), TEST_CASE(elosTestElosFindEventsExtErrVerifySession), + TEST_CASE(elosTestElosFindEventsExtErrNewObject), TEST_CASE(elosTestElosFindEventsExtErrAddNewString), + TEST_CASE(elosTestElosFindEventsExtErrAddNewTimestamp), TEST_CASE(elosTestElosFindEventsExtErrCommunication), + TEST_CASE(elosTestElosFindEventsExtErrVectorFromJsonArr), TEST_CASE(elosTestElosFindEventsSuccess), + TEST_CASE(elosTestElosFindEventsSuccessTruncated), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +void elosFindEventsUtestCreateSession(void **state) { + elosUteststateT_t *testState = *state; + testState->session = safuAllocMem(NULL, sizeof(elosSession_t)); + testState->session->fd = VALID_SESSION_FD; + testState->session->connected = true; + assert_non_null(testState->session); +} + +void elosFindEventsUtestFreeSession(void **state) { + elosUteststateT_t *testState = *state; + free(testState->session); +} + +int _verifyExpectedRequest(const LargestIntegralType request, const LargestIntegralType testState) { + elosUteststateT_t *state = (elosUteststateT_t *)testState; + json_object *actualJsonRequest = (json_object *)request; + int isEqual = json_object_equal(actualJsonRequest, state->expectedJsonRequest[state->requestCount]); + if (isEqual == 0) { + print_error("Request is not as expected: actual '%s' != expected '%s'\n", + json_object_to_json_string(actualJsonRequest), + json_object_to_json_string(state->expectedJsonRequest[state->requestCount])); + } + state->requestCount++; + return isEqual; +} + +void elosMockSendAndReceiveJsonMessage(elosUteststateT_t *test, size_t callCount, safuResultE_t result) { + MOCK_FUNC_ALWAYS(elosSendAndReceiveJsonMessage); + for (size_t i = 0; i < callCount; i++) { + expect_value(elosSendAndReceiveJsonMessage, session, test->session); + expect_value(elosSendAndReceiveJsonMessage, messageId, ELOS_MESSAGE_LOG_FIND_EVENT); + expect_check(elosSendAndReceiveJsonMessage, sendJsonObject, _verifyExpectedRequest, test); + + expect_not_value(elosSendAndReceiveJsonMessage, receiveJsonObject, NULL); + will_set_parameter(elosSendAndReceiveJsonMessage, receiveJsonObject, test->expectedJsonResponse[i]); + will_return(elosSendAndReceiveJsonMessage, result); + } +} + +void elosCleanupMockSendAndReceiveJsonMessage(elosUteststateT_t *test) { + for (size_t i = 0; i < test->requestCount; i++) { + if (test->expectedJsonRequest[i] != NULL) { + json_object_put(test->expectedJsonRequest[i]); + } + // testState->expectedJsonResponse is freed by the implementation + } + free(test->expectedJsonResponse); + free(test->expectedJsonRequest); + MOCK_FUNC_NEVER(elosSendAndReceiveJsonMessage); +} diff --git a/test/utest/libelos/elosFindEvents/elosFindEvents_utest.h b/test/utest/libelos/elosFindEvents/elosFindEvents_utest.h new file mode 100644 index 00000000..f6a68c7b --- /dev/null +++ b/test/utest/libelos/elosFindEvents/elosFindEvents_utest.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +#pragma once + +#include +#include +#include + +#include "elos/event/event_types.h" +#include "elos/libelos/libelos.h" + +#define VALID_SESSION_FD 42 +#define INVALID_SESSION_FD (-1) + +typedef struct { + elosSession_t *session; + size_t requestCount; // incremented by mock + json_object **expectedJsonRequest; + json_object **expectedJsonResponse; + elosEventVector_t *eventVector; +} elosUteststateT_t; + +void elosFindEventsUtestCreateSession(void **state); +void elosFindEventsUtestFreeSession(void **state); + +void elosMockSendAndReceiveJsonMessage(elosUteststateT_t *test, size_t callCount, safuResultE_t result); +void elosCleanupMockSendAndReceiveJsonMessage(elosUteststateT_t *test); + +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsErrInvalidParameter) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrVerifySession) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrNewObject) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrAddNewString) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrAddNewTimestamp) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrCommunication) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsExtErrVectorFromJsonArr) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsSuccess) +TEST_CASE_FUNC_PROTOTYPES(elosTestElosFindEventsSuccessTruncated) diff --git a/test/utest/mocks/libelos/mock_libelos.c b/test/utest/mocks/libelos/mock_libelos.c index 660aeb91..421410d2 100644 --- a/test/utest/mocks/libelos/mock_libelos.c +++ b/test/utest/mocks/libelos/mock_libelos.c @@ -52,6 +52,27 @@ MOCK_FUNC_BODY(elosGetVersion, safuResultE_t, elosSession_t *session, const char return result; } +MOCK_FUNC_BODY(elosFindEvents, safuResultE_t, elosSession_t *session, const char *filterRule, + struct timespec const *newest, struct timespec const *oldest, elosEventVector_t **vector) { + safuResultE_t result; + + if (MOCK_IS_ACTIVE(elosLogFindEvent)) { + check_expected_ptr(session); + check_expected_ptr(filterRule); + check_expected_ptr(newest); + check_expected_ptr(oldest); + check_expected_ptr(vector); + if (vector != NULL) { + *vector = mock_type(elosEventVector_t *); + } + result = mock_type(safuResultE_t); + } else { + result = MOCK_FUNC_REAL(elosFindEvents)(session, filterRule, newest, oldest, vector); + } + + return result; +} + MOCK_FUNC_BODY(elosLogFindEvent, safuResultE_t, elosSession_t *session, const char *filterRule, elosEventVector_t **vector) { safuResultE_t result; diff --git a/test/utest/mocks/libelos/mock_libelos.h b/test/utest/mocks/libelos/mock_libelos.h index 2a91aae3..17298f5b 100644 --- a/test/utest/mocks/libelos/mock_libelos.h +++ b/test/utest/mocks/libelos/mock_libelos.h @@ -20,6 +20,9 @@ MOCK_FUNC_PROTOTYPE(elosGetVersion, safuResultE_t, elosSession_t *session, const MOCK_FUNC_PROTOTYPE(elosLogFindEvent, safuResultE_t, elosSession_t *session, const char *filterRule, elosEventVector_t **vector) +MOCK_FUNC_PROTOTYPE(elosFindEvents, safuResultE_t, elosSession_t *session, const char *filterRule, + struct timespec const *newest, struct timespec const *oldest, elosEventVector_t **vector) + MOCK_FUNC_PROTOTYPE(elosSessionValid, bool, elosSession_t const *session) MOCK_FUNC_PROTOTYPE(elosEventSubscribe, safuResultE_t, elosSession_t *session, char const **filterRuleArray,