From bf0970149a6909dc18a408f2eb0360a91d06161b Mon Sep 17 00:00:00 2001 From: Jan Michalski Date: Thu, 29 Feb 2024 23:36:45 -0500 Subject: [PATCH] test: introduce core_log() unit tests Signed-off-by: Jan Michalski --- src/core/log_internal.h | 14 -- src/test/Makefile | 4 +- src/test/core_log/.gitignore | 1 + src/test/core_log/Makefile | 7 + src/test/core_log/Makefile.inc | 12 + src/test/core_log/TESTS.py | 47 ++++ src/test/core_log/core_log.c | 224 ++++++++++++++++++ src/test/core_log/core_log_common.c | 163 +++++++++++++ src/test/core_log/core_log_common.h | 62 +++++ .../core_log_internal/core_log_internal.c | 2 +- src/test/core_log_no_func/.gitignore | 1 + src/test/core_log_no_func/Makefile | 10 + src/test/core_log_no_func/TESTS.py | 27 +++ src/test/core_log_no_func/core_log_no_func.c | 67 ++++++ src/test/unittest/unittest.h | 2 +- 15 files changed, 626 insertions(+), 17 deletions(-) create mode 100644 src/test/core_log/.gitignore create mode 100644 src/test/core_log/Makefile create mode 100644 src/test/core_log/Makefile.inc create mode 100755 src/test/core_log/TESTS.py create mode 100644 src/test/core_log/core_log.c create mode 100644 src/test/core_log/core_log_common.c create mode 100644 src/test/core_log/core_log_common.h create mode 100644 src/test/core_log_no_func/.gitignore create mode 100644 src/test/core_log_no_func/Makefile create mode 100755 src/test/core_log_no_func/TESTS.py create mode 100644 src/test/core_log_no_func/core_log_no_func.c diff --git a/src/core/log_internal.h b/src/core/log_internal.h index 8f78558426a..2d03c1b3fa4 100644 --- a/src/core/log_internal.h +++ b/src/core/log_internal.h @@ -83,20 +83,6 @@ typedef void core_log_function( int core_log_set_function(core_log_function *log_function, void *context); -/* pointer to the logging function */ -extern -#ifdef ATOMIC_OPERATIONS_SUPPORTED -_Atomic -#endif /* ATOMIC_OPERATIONS_SUPPORTED */ -uintptr_t Core_log_function; - -/* the logging function's context */ -extern -#ifdef ATOMIC_OPERATIONS_SUPPORTED -_Atomic -#endif /* ATOMIC_OPERATIONS_SUPPORTED */ -void *Core_log_function_context; - /* threshold levels */ extern #ifdef ATOMIC_OPERATIONS_SUPPORTED diff --git a/src/test/Makefile b/src/test/Makefile index 6e0107d44c0..0f96dc0167f 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -107,10 +107,12 @@ OBJ_TESTS = \ OTHER_TESTS = \ arch_flags\ - core_log_internal\ + core_log\ core_log_default_function\ + core_log_internal\ core_log_max\ core_log_mt\ + core_log_no_func\ checksum\ compat_incompat_features\ ctl_prefault\ diff --git a/src/test/core_log/.gitignore b/src/test/core_log/.gitignore new file mode 100644 index 00000000000..077e6928a11 --- /dev/null +++ b/src/test/core_log/.gitignore @@ -0,0 +1 @@ +core_log diff --git a/src/test/core_log/Makefile b/src/test/core_log/Makefile new file mode 100644 index 00000000000..0067f595c8d --- /dev/null +++ b/src/test/core_log/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +TARGET = core_log +OBJS = core_log.o core_log_common.o + +include ./Makefile.inc diff --git a/src/test/core_log/Makefile.inc b/src/test/core_log/Makefile.inc new file mode 100644 index 00000000000..7eb23ab70c0 --- /dev/null +++ b/src/test/core_log/Makefile.inc @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +BUILD_STATIC_DEBUG=n +BUILD_STATIC_NONDEBUG=n + +# 'internal' is required for proper mock integration +# 'debug' provides 'out_log()' required for 'ut_log_function()' +LIBPMEMCORE=internal-debug + +include ../Makefile.inc +LDFLAGS += $(call extract_funcs, ../core_log/core_log_common.c) diff --git a/src/test/core_log/TESTS.py b/src/test/core_log/TESTS.py new file mode 100755 index 00000000000..975d3d5cc73 --- /dev/null +++ b/src/test/core_log/TESTS.py @@ -0,0 +1,47 @@ +#!../env.py +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation +# + + +import testframework as t +from testframework import granularity as g + + +@g.require_granularity(g.ANY) +# The 'nondebug' build is chosen arbitrarily to ensure these tests are run only +# once. No dynamic libraries are used nor .static_* builds are available. +@t.require_build('nondebug') +class CORE_LOG(t.BaseTest): + test_type = t.Short + + def run(self, ctx): + ctx.exec('core_log', self.test_case) + + +class TEST0(CORE_LOG): + test_case = 'test_CORE_LOG_LEVEL_ERROR_LAST' + + +class TEST1(CORE_LOG): + test_case = 'test_vsnprintf_fail' + + +class TEST2(CORE_LOG): + test_case = 'test_NO_ERRNO' + + +class TEST3(CORE_LOG): + test_case = 'test_no_space_for_strerror_r' + + +class TEST4(CORE_LOG): + test_case = 'test_strerror_r_fail' + + +class TEST5(CORE_LOG): + test_case = 'test_level_gt_threshold' + + +class TEST6(CORE_LOG): + test_case = 'test_happy_day' diff --git a/src/test/core_log/core_log.c b/src/test/core_log/core_log.c new file mode 100644 index 00000000000..3263668ca40 --- /dev/null +++ b/src/test/core_log/core_log.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2024, Intel Corporation */ + +/* + * core_log.c -- unit test for core_log() and core_log_va() + */ + +#include + +#include "last_error_msg.h" +#include "unittest.h" + +#include "core_log_common.h" + +/* tests */ + +/* + * Check: + * - CORE_LOG_LEVEL_ERROR_LAST -> CORE_LOG_LEVEL_ERROR + * - buf == last_error_msg_get(); + * - buf_len == CORE_LAST_ERROR_MSG_MAXPRINT + */ +static int +test_CORE_LOG_LEVEL_ERROR_LAST(const struct test_case *tc, int argc, + char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + reset_mocks(); + + /* set the expectations */ + Common.use_last_error_msg = true; + Vsnprintf_.ret = 0; /* empty but successful */ + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + + core_log(CORE_LOG_LEVEL_ERROR_LAST, NO_ERRNO, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), CALLED); + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - The log preparation stops after the failed vsnprintf() call. + * - The log function is not called. + */ +static int +test_vsnprintf_fail(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = -1; /* negative value if an output error */ + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + Common.use_last_error_msg = false; + + core_log(CORE_LOG_LEVEL_ERROR, NO_ERRNO, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), NOT_CALLED); + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - NO_ERRNO means no strerror_r() call. + * - The produced log message is passed to the log function. + */ +static int +test_NO_ERRNO(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = 0; /* leave a lot of space for the error string */ + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + Common.use_last_error_msg = false; + + core_log(CORE_LOG_LEVEL_ERROR, NO_ERRNO, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), CALLED); + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - fully fill the provided buffer in three ways: + * (1) exactly (`- 1` for the terminating null-byte) + * (2) one character too many (the null-byte would end up just after + * the actual buffer space) + * (3) two characters too many (no space for one character of the message and + * for the null-byte) + * - the strerror_r() is not called despite an errno is provided. + */ +static int +test_no_space_for_strerror_r(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + for (int i = _CORE_LOG_MSG_MAXPRINT - 1; + i <= _CORE_LOG_MSG_MAXPRINT + 1; ++i) { + test_no_space_for_strerror_r_helper(i); + } + + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - strerror_r() fails in two ways: + * (1) before glibc 2.13 + * (2) since glibc 2.13 + * - The produced log message is passed to the log function. + */ +static int +test_strerror_r_fail(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + test_strerror_r_fail_helper(true); + test_strerror_r_fail_helper(false); + + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - if level <= threshold: + * - the log function is called + * - else: + * - the log function is not called + */ +static int +test_level_gt_threshold(const struct test_case *tc, int argc, char *argv[]) +{ + for (enum core_log_level threshold = CORE_LOG_LEVEL_HARK; + threshold < CORE_LOG_LEVEL_MAX; ++threshold) { + core_log_set_threshold(CORE_LOG_THRESHOLD, threshold); + + for (enum core_log_level level = CORE_LOG_LEVEL_HARK; + level < CORE_LOG_LEVEL_MAX; ++level) { + bool log_function_called = (level <= threshold); + test_log_function_call_helper(level, + log_function_called); + } + } + + return NO_ARGS_CONSUMED; +} + +static int +test_happy_day(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = BASIC_MESSAGE_LEN; + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + Common.use_last_error_msg = true; + Strerror_r.exp__buf = LAST_ERROR_MSG_MOCK + Vsnprintf_.ret; + Strerror_r.exp__buflen = CORE_LAST_ERROR_MSG_MAXPRINT - + (size_t)Vsnprintf_.ret; + Strerror_r.error = EXIT_SUCCESS; + + core_log(CORE_LOG_LEVEL_ERROR_LAST, DUMMY_ERRNO1, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), CALLED); + + return NO_ARGS_CONSUMED; +} + +static struct test_case test_cases[] = { + TEST_CASE(test_CORE_LOG_LEVEL_ERROR_LAST), + TEST_CASE(test_vsnprintf_fail), + TEST_CASE(test_NO_ERRNO), + TEST_CASE(test_no_space_for_strerror_r), + TEST_CASE(test_strerror_r_fail), + TEST_CASE(test_level_gt_threshold), + TEST_CASE(test_happy_day), +}; + +#define NTESTS ARRAY_SIZE(test_cases) + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "core_log"); + core_log_set_function(CORE_LOG_USE_DEFAULT_FUNCTION, NULL); + openlog(NULL, LOG_NDELAY, LOG_USER); + TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); + closelog(); + DONE(NULL); +} diff --git a/src/test/core_log/core_log_common.c b/src/test/core_log/core_log_common.c new file mode 100644 index 00000000000..8b804de46f2 --- /dev/null +++ b/src/test/core_log/core_log_common.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2024, Intel Corporation */ + +/* + * core_log_common.c -- mocks and helpers common for core_log(_no_func) + */ + +#include "last_error_msg.h" +#include "unittest.h" + +#include "core_log_common.h" + +/* mocks */ + +struct common_ctx Common; +struct vsnprintf_ctx Vsnprintf_; +struct strerror_r_ctx Strerror_r; +struct log_function_ctx Log_function_; + +FUNC_MOCK(last_error_msg_get, const char *, void) +FUNC_MOCK_RUN_DEFAULT { + return LAST_ERROR_MSG_MOCK; +} +FUNC_MOCK_END + +FUNC_MOCK(vsnprintf, int, char *__restrict __s, size_t __maxlen, + const char *__restrict __format, va_list __arg) + FUNC_MOCK_RUN(VALIDATED_CALL) { + if (Common.use_last_error_msg) { + UT_ASSERTeq(__s, LAST_ERROR_MSG_MOCK); + UT_ASSERTeq(__maxlen, CORE_LAST_ERROR_MSG_MAXPRINT); + } else { + UT_ASSERTne(__s, LAST_ERROR_MSG_MOCK); + UT_ASSERTeq(__maxlen, _CORE_LOG_MSG_MAXPRINT); + } + UT_ASSERT(__format == MSG_FORMAT); + (void) __arg; + + return Vsnprintf_.ret; + } +FUNC_MOCK_RUN_DEFAULT { + return _FUNC_REAL(vsnprintf)(__s, __maxlen, __format, __arg); +} +FUNC_MOCK_END + +FUNC_MOCK(__xpg_strerror_r, int, int __errnum, char *__buf, size_t __buflen) +FUNC_MOCK_RUN_DEFAULT { + UT_ASSERTeq(__errnum, DUMMY_ERRNO1); + UT_ASSERTeq(__buf, Strerror_r.exp__buf); + UT_ASSERTeq(__buflen, Strerror_r.exp__buflen); + + if (Strerror_r.error == EXIT_SUCCESS) { + return 0; + } + + if (Strerror_r.before_glibc_2_13) { + errno = Strerror_r.error; + return -1; + } else { + return Strerror_r.error; + } +} +FUNC_MOCK_END + +FUNC_MOCK(core_log_default_function, void, void *context, + enum core_log_level level, const char *file_name, const int line_no, + const char *function_name, const char *message) + FUNC_MOCK_RUN(VALIDATED_CALL) { + UT_ASSERTeq(context, NULL); + UT_ASSERTeq(level, Log_function_.exp_level); + UT_ASSERTstreq(file_name, FILE_NAME); + UT_ASSERTeq(line_no, LINE_NO); + UT_ASSERTstreq(function_name, FUNC_NAME); + if (Common.use_last_error_msg) { + UT_ASSERTeq(message, LAST_ERROR_MSG_MOCK); + } else { + UT_ASSERTne(message, LAST_ERROR_MSG_MOCK); + } + return; + } +FUNC_MOCK_RUN_DEFAULT { + _FUNC_REAL(core_log_default_function)(context, level, file_name, + line_no, function_name, message); +} +FUNC_MOCK_END + +/* helpers */ + +void +reset_mocks(void) +{ + FUNC_MOCK_RCOUNTER_SET(last_error_msg_get, VALIDATED_CALL); + FUNC_MOCK_RCOUNTER_SET(vsnprintf, VALIDATED_CALL); + FUNC_MOCK_RCOUNTER_SET(__xpg_strerror_r, VALIDATED_CALL); + FUNC_MOCK_RCOUNTER_SET(core_log_default_function, VALIDATED_CALL); +} + +void +test_no_space_for_strerror_r_helper(int core_message_length) +{ + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = core_message_length; + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + Common.use_last_error_msg = false; + + core_log(CORE_LOG_LEVEL_ERROR, DUMMY_ERRNO1, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), CALLED); +} + +void +test_strerror_r_fail_helper(bool before_glibc_2_13) +{ + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = BASIC_MESSAGE_LEN; + Log_function_.exp_level = CORE_LOG_LEVEL_ERROR; + Common.use_last_error_msg = true; + Strerror_r.exp__buf = LAST_ERROR_MSG_MOCK + Vsnprintf_.ret; + Strerror_r.exp__buflen = CORE_LAST_ERROR_MSG_MAXPRINT - + (size_t)Vsnprintf_.ret; + Strerror_r.error = DUMMY_ERRNO2; + Strerror_r.before_glibc_2_13 = before_glibc_2_13; + + core_log(CORE_LOG_LEVEL_ERROR_LAST, DUMMY_ERRNO1, FILE_NAME, LINE_NO, + FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), CALLED); +} + +void +test_log_function_call_helper(enum core_log_level level, + bool log_function_called) +{ + reset_mocks(); + + /* set the expectations */ + Vsnprintf_.ret = BASIC_MESSAGE_LEN; + Log_function_.exp_level = level; + Common.use_last_error_msg = (level == CORE_LOG_LEVEL_ERROR_LAST); + + core_log(level, NO_ERRNO, FILE_NAME, LINE_NO, FUNC_NAME, MSG_FORMAT); + + /* check the call counters */ + UT_ASSERTeq(RCOUNTER(last_error_msg_get), + Common.use_last_error_msg ? CALLED : NOT_CALLED); + UT_ASSERTeq(RCOUNTER(vsnprintf), CALLED); + UT_ASSERTeq(RCOUNTER(__xpg_strerror_r), NOT_CALLED); + UT_ASSERTeq(RCOUNTER(core_log_default_function), + log_function_called ? CALLED : NOT_CALLED); +} diff --git a/src/test/core_log/core_log_common.h b/src/test/core_log/core_log_common.h new file mode 100644 index 00000000000..bb6307fee41 --- /dev/null +++ b/src/test/core_log/core_log_common.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright 2024, Intel Corporation */ + +/* + * core_log.c -- definitions for mocks and helpers common for core_log(_no_func) + */ + +#include + +#include "unittest.h" + +#define NO_ARGS_CONSUMED 0 + +#define FILE_NAME "dummy.c" +#define LINE_NO 1234 +#define FUNC_NAME "dummy_func" +#define MSG_FORMAT ((char *)0x0458f044) +#define LAST_ERROR_MSG_MOCK ((char *)0x1a547e58) +#define DUMMY_ERRNO1 500 +#define DUMMY_ERRNO2 (DUMMY_ERRNO1 + 1) +#define BASIC_MESSAGE_LEN 131 + +#define VALIDATED_CALL 127 +#define NOT_CALLED VALIDATED_CALL +#define CALLED (VALIDATED_CALL + 1) + +extern struct common_ctx { + bool use_last_error_msg; +} Common; + +extern struct vsnprintf_ctx { + int ret; +} Vsnprintf_; + +extern struct strerror_r_ctx { + char *exp__buf; + size_t exp__buflen; + bool before_glibc_2_13; + int error; +} Strerror_r; + +extern struct log_function_ctx { + enum core_log_level exp_level; +} Log_function_; + +/* mocks */ + +extern unsigned RCOUNTER(last_error_msg_get); +extern unsigned RCOUNTER(vsnprintf); +extern unsigned RCOUNTER(__xpg_strerror_r); +extern unsigned RCOUNTER(core_log_default_function); + +/* helpers */ + +void reset_mocks(void); + +void test_no_space_for_strerror_r_helper(int core_message_length); + +void test_strerror_r_fail_helper(bool before_glibc_2_13); + +void test_log_function_call_helper(enum core_log_level level, + bool call_log_function); diff --git a/src/test/core_log_internal/core_log_internal.c b/src/test/core_log_internal/core_log_internal.c index 67220f4ff4f..6fd1af8d5a4 100644 --- a/src/test/core_log_internal/core_log_internal.c +++ b/src/test/core_log_internal/core_log_internal.c @@ -254,7 +254,7 @@ main(int argc, char *argv[]) core_log_get_threshold(CORE_LOG_THRESHOLD, &Core_log_default_threshold); core_log_set_function(CORE_LOG_USE_DEFAULT_FUNCTION, NULL); - START(argc, argv, "core_log"); + START(argc, argv, "core_log_internal"); TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); DONE(NULL); } diff --git a/src/test/core_log_no_func/.gitignore b/src/test/core_log_no_func/.gitignore new file mode 100644 index 00000000000..18f74694106 --- /dev/null +++ b/src/test/core_log_no_func/.gitignore @@ -0,0 +1 @@ +core_log_no_func diff --git a/src/test/core_log_no_func/Makefile b/src/test/core_log_no_func/Makefile new file mode 100644 index 00000000000..cfa23ac02f5 --- /dev/null +++ b/src/test/core_log_no_func/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +vpath %.c ../core_log + +TARGET = core_log_no_func +OBJS = core_log_no_func.o core_log_common.o + +include ../core_log/Makefile.inc +INCS += -I../core_log diff --git a/src/test/core_log_no_func/TESTS.py b/src/test/core_log_no_func/TESTS.py new file mode 100755 index 00000000000..55c52d048d8 --- /dev/null +++ b/src/test/core_log_no_func/TESTS.py @@ -0,0 +1,27 @@ +#!../env.py +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation +# + + +import testframework as t +from testframework import granularity as g + + +@g.require_granularity(g.ANY) +# The 'nondebug' build is chosen arbitrarily to ensure these tests are run only +# once. No dynamic libraries are used nor .static_* builds are available. +@t.require_build('nondebug') +class CORE_LOG(t.BaseTest): + test_type = t.Short + + def run(self, ctx): + ctx.exec('core_log_no_func', self.test_case) + + +class TEST0(CORE_LOG): + test_case = 'test_no_log_function' + + +class TEST1(CORE_LOG): + test_case = 'test_no_log_function_CORE_LOG_LEVEL_ERROR_LAST' diff --git a/src/test/core_log_no_func/core_log_no_func.c b/src/test/core_log_no_func/core_log_no_func.c new file mode 100644 index 00000000000..4b64500f845 --- /dev/null +++ b/src/test/core_log_no_func/core_log_no_func.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2024, Intel Corporation */ + +/* + * core_log_no_func.c -- unit test for core_log() and core_log_va() when + * no logging function is attached. + */ + +#include + +#include "unittest.h" +#include "core_log_common.h" + +/* tests */ + +/* + * Check: + * - if Core_log_function == 0: + * - the log function is not called + */ +static int +test_no_log_function(const struct test_case *tc, int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + test_log_function_call_helper(CORE_LOG_LEVEL_ERROR, + false /* log_function_called */); + + return NO_ARGS_CONSUMED; +} + +/* + * Check: + * - if Core_log_function == 0 and level == CORE_LOG_LEVEL_ERROR_LAST: + * - the log function is not called + */ +static int +test_no_log_function_CORE_LOG_LEVEL_ERROR_LAST(const struct test_case *tc, + int argc, char *argv[]) +{ + /* Pass the message all the way to the logging function. */ + core_log_set_threshold(CORE_LOG_THRESHOLD, CORE_LOG_LEVEL_ERROR); + + test_log_function_call_helper(CORE_LOG_LEVEL_ERROR_LAST, + false /* log_function_called */); + + return NO_ARGS_CONSUMED; +} + +static struct test_case test_cases[] = { + TEST_CASE(test_no_log_function), + TEST_CASE(test_no_log_function_CORE_LOG_LEVEL_ERROR_LAST), +}; + +#define NTESTS ARRAY_SIZE(test_cases) + +#undef LOG_SET_PMEMCORE_FUNC +#define LOG_SET_PMEMCORE_FUNC + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "core_log_no_func"); + TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); + DONE(NULL); +} diff --git a/src/test/unittest/unittest.h b/src/test/unittest/unittest.h index 78d144a52d4..a01a791e61f 100644 --- a/src/test/unittest/unittest.h +++ b/src/test/unittest/unittest.h @@ -559,7 +559,7 @@ int ut_thread_join(const char *file, int line, const char *func, #define FUNC_MOCK(name, ret_type, ...)\ _FUNC_REAL_DECL(name, ret_type, ##__VA_ARGS__)\ - static unsigned RCOUNTER(name);\ + unsigned RCOUNTER(name);\ ret_type __wrap_##name(__VA_ARGS__);\ ret_type __wrap_##name(__VA_ARGS__) {\ switch (util_fetch_and_add32(&RCOUNTER(name), 1)) {