The CUnit test infrastructure is integrated in trace-cmd. http://cunit.sourceforge.net/ The library and its headers must be installed on the machine, in order to build the trace-cmd unit tests. For Fedora, these packages must be installed: CUnit, CUnit-devel A new directory is added: utest containing unit tests implementation. Added new target to trace-cmd top Makefile: make test which builds the unit test binary: utest/trace-utest The goal of this patch is not to provide full unit test coverage of libtracefs, but to be a POC for adding test infrastructure to trace-cmd. The first API, covered be the test is: tracefs_iterate_raw_events() Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@xxxxxxxxx> --- Makefile | 13 ++++- utest/Makefile | 41 ++++++++++++++ utest/README | 15 +++++ utest/trace-utest.c | 83 ++++++++++++++++++++++++++++ utest/trace-utest.h | 11 ++++ utest/tracefs-utest.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 utest/Makefile create mode 100644 utest/README create mode 100644 utest/trace-utest.c create mode 100644 utest/trace-utest.h create mode 100644 utest/tracefs-utest.c diff --git a/Makefile b/Makefile index 477625f..ddf52ea 100644 --- a/Makefile +++ b/Makefile @@ -200,7 +200,7 @@ TRACE_LIBS = -L$(LIBTRACECMD_DIR) -ltracecmd \ -L$(LIBTRACEFS_DIR) -ltracefs export LIBS TRACE_LIBS -export LIBTRACEEVENT_DIR LIBTRACECMD_DIR +export LIBTRACEEVENT_DIR LIBTRACECMD_DIR LIBTRACEFS_DIR export LIBTRACECMD_STATIC LIBTRACECMD_SHARED export LIBTRACEEVENT_STATIC LIBTRACEEVENT_SHARED export LIBTRACEFS_STATIC LIBTRACEFS_SHARED @@ -234,6 +234,9 @@ ifeq ($(VSOCK_DEFINED), 1) CFLAGS += -DVSOCK endif +CUNIT_INSTALLED := $(shell if (echo -e "\#include <CUnit/Basic.h>\n void main(){CU_initialize_registry();}" | $(CC) -x c -lcunit - >/dev/null 2>&1) ; then echo 1; else echo 0 ; fi) +export CUNIT_INSTALLED + export CFLAGS export INCLUDES @@ -319,7 +322,6 @@ $(LIBTRACEFS_STATIC): force $(LIBTRACEFS_SHARED): force $(Q)$(MAKE) -C $(src)/lib/tracefs $@ - libtraceevent.so: $(LIBTRACEEVENT_SHARED) libtraceevent.a: $(LIBTRACEEVENT_STATIC) libtracecmd.a: $(LIBTRACECMD_STATIC) @@ -329,6 +331,12 @@ libtracefs.so: $(LIBTRACEFS_SHARED) libs: $(LIBTRACECMD_SHARED) $(LIBTRACEEVENT_SHARED) $(LIBTRACEFS_SHARED) +test: force $(LIBTRACEEVENT_STATIC) $(LIBTRACEFS_STATIC) $(LIBTRACECMD_STATIC) +ifneq ($(CUNIT_INSTALLED),1) + $(error CUnit framework not installed, cannot build unit tests)) +endif + $(Q)$(MAKE) -C $(src)/utest $@ + plugins_traceevent: force $(obj)/lib/traceevent/plugins/traceevent_plugin_dir \ $(obj)/lib/traceevent/plugins/trace_python_dir $(Q)$(MAKE) -C $(src)/lib/traceevent/plugins @@ -430,6 +438,7 @@ clean: $(MAKE) -C $(src)/lib/tracefs clean $(MAKE) -C $(src)/lib/traceevent/plugins clean $(MAKE) -C $(src)/lib/trace-cmd/plugins clean + $(MAKE) -C $(src)/utest clean $(MAKE) -C $(src)/python clean $(MAKE) -C $(src)/tracecmd clean if [ -f $(kshark-dir)/build/Makefile ]; then $(MAKE) -C $(kshark-dir)/build clean; fi diff --git a/utest/Makefile b/utest/Makefile new file mode 100644 index 0000000..55aa46a --- /dev/null +++ b/utest/Makefile @@ -0,0 +1,41 @@ + +include $(src)/scripts/utils.mk + +bdir:=$(obj)/utest + +TARGETS = $(bdir)/trace-utest + +OBJS = +OBJS += trace-utest.o +OBJS += tracefs-utest.o + +LIBS += -lcunit \ + -L$(LIBTRACEFS_DIR) -ltracefs \ + -L$(LIBTRACEEVENT_DIR) -ltraceevent + +OBJS := $(OBJS:%.o=$(bdir)/%.o) +DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) + +$(bdir): + @mkdir -p $(bdir) + +$(OBJS): | $(bdir) +$(DEPS): | $(bdir) + +$(bdir)/trace-utest: $(OBJS) + $(Q)$(do_app_build) + +$(bdir)/%.o: %.c + $(Q)$(call do_fpic_compile) + +$(DEPS): $(bdir)/.%.d: %.c + $(Q)$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@ + +$(OBJS): $(bdir)/%.o : $(bdir)/.%.d + +dep_includes := $(wildcard $(DEPS)) + +test: $(TARGETS) + +clean: + $(RM) $(TARGETS) $(bdir)/*.o $(bdir)/.*.d diff --git a/utest/README b/utest/README new file mode 100644 index 0000000..f93630d --- /dev/null +++ b/utest/README @@ -0,0 +1,15 @@ + +Unit tests for trace-cmd libraries. The tests use CUnit framework: + http://cunit.sourceforge.net/ +which must be pre installed on the system, before building the unit tests. +The framework can be downloaded, compiled and installed manually, or +using a precompiled distro package: + + Fedora: + CUnit + CUnit-devel + + Ubuntu and Debian: + libcunit1 + libcunit1-doc + libcunit1-dev diff --git a/utest/trace-utest.c b/utest/trace-utest.c new file mode 100644 index 0000000..58d4d4e --- /dev/null +++ b/utest/trace-utest.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@xxxxxxxxx> + * + */ +#include <stdio.h> +#include <unistd.h> +#include <getopt.h> +#include <stdlib.h> + +#include <CUnit/CUnit.h> +#include <CUnit/Basic.h> + +#include "trace-utest.h" + +enum unit_tests { + RUN_NONE = 0, + RUN_TRACEFS = (1 << 0), + RUN_ALL = 0xFFFF +}; + +static void print_help(char **argv) +{ + printf("Usage: %s [OPTIONS]\n", basename(argv[0])); + printf("\t-s, --silent\tPrint test summary\n"); + printf("\t-r, --run test\tRun specific test:\n"); + printf("\t\t tracefs run libtracefs tests\n"); + printf("\t-h, --help\tPrint usage information\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + CU_BasicRunMode verbose = CU_BRM_VERBOSE; + enum unit_tests tests = RUN_NONE; + + for (;;) { + int c; + int index = 0; + const char *opts = "+hsr:"; + static struct option long_options[] = { + {"silent", no_argument, NULL, 's'}, + {"run", required_argument, NULL, 'r'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long (argc, argv, opts, long_options, &index); + if (c == -1) + break; + switch (c) { + case 'r': + if (strcmp(optarg, "tracefs") == 0) + tests |= RUN_TRACEFS; + else + print_help(argv); + break; + case 's': + verbose = CU_BRM_SILENT; + break; + case 'h': + default: + print_help(argv); + break; + } + } + + if (tests == RUN_NONE) + tests = RUN_ALL; + + if (CU_initialize_registry() != CUE_SUCCESS) { + printf("Test registry cannot be initialized\n"); + return -1; + } + + if (tests & RUN_TRACEFS) + test_tracefs_lib(); + + CU_basic_set_mode(verbose); + CU_basic_run_tests(); + CU_cleanup_registry(); + return 0; +} diff --git a/utest/trace-utest.h b/utest/trace-utest.h new file mode 100644 index 0000000..917c0e7 --- /dev/null +++ b/utest/trace-utest.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@xxxxxxxxx> + * + */ +#ifndef _TRACE_UTEST_H_ +#define _TRACE_UTEST_H_ + +void test_tracefs_lib(void); + +#endif /* _TRACE_UTEST_H_ */ diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c new file mode 100644 index 0000000..d3ba213 --- /dev/null +++ b/utest/tracefs-utest.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@xxxxxxxxx> + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <CUnit/CUnit.h> +#include <CUnit/Basic.h> + +#include "tracefs.h" + +#define TRACEFS_SUITE "trasefs library" +#define TEST_INSTANCE_NAME "cunit_test_iter" +#define TEST_ARRAY_SIZE 50 + +static struct tracefs_instance *test_instance; +static struct tep_handle *test_tep; +static int test_array[TEST_ARRAY_SIZE]; +static int test_found; + +static int test_callback(struct tep_event *event, struct tep_record *record, + int cpu, void *context) +{ + struct tep_format_field *field; + int val, i; + + field = tep_find_field(event, "buf"); + if (field) { + val = *((int *)(record->data + field->offset)); + for (i = 0; i < TEST_ARRAY_SIZE; i++) { + if (test_array[i] == val) { + test_array[i] = 0; + test_found++; + break; + } + } + } + + return 0; +} + +static void test_iter_write(void) +{ + char *path; + int i, fd; + int ret; + + path = tracefs_instance_get_file(test_instance, "trace_marker"); + CU_TEST(path != NULL); + fd = open(path, O_WRONLY); + CU_TEST(fd >= 0); + + for (i = 0; i < TEST_ARRAY_SIZE; i++) { + test_array[i] = random(); + ret = write(fd, test_array + i, sizeof(int)); + CU_TEST(ret == sizeof(int)); + } + + tracefs_put_tracing_file(path); + close(fd); +} + + +static void test_iter_raw_events(void) +{ + int ret; + + ret = tracefs_iterate_raw_events(NULL, test_instance, test_callback, NULL); + CU_TEST(ret < 0); + ret = tracefs_iterate_raw_events(test_tep, NULL, test_callback, NULL); + CU_TEST(ret == 0); + ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, NULL); + CU_TEST(ret < 0); + + test_found = 0; + test_iter_write(); + ret = tracefs_iterate_raw_events(test_tep, test_instance, + test_callback, NULL); + CU_TEST(ret == 0); + CU_TEST(test_found == TEST_ARRAY_SIZE); +} + +static int test_suite_destroy(void) +{ + tracefs_instance_destroy(test_instance); + tracefs_instance_free(test_instance); + tep_free(test_tep); + return 0; +} + +static int test_suite_init(void) +{ + const char *systems[] = {"ftrace", NULL}; + + test_tep = tracefs_local_events_system(NULL, systems); + if (test_tep == NULL) + return 1; + + test_instance = tracefs_instance_alloc(TEST_INSTANCE_NAME); + if (test_instance == NULL) + return 1; + + if (tracefs_instance_create(test_instance) < 0) + return 1; + + return 0; +} + +void test_tracefs_lib(void) +{ + CU_pSuite suite = NULL; + + suite = CU_add_suite(TRACEFS_SUITE, test_suite_init, test_suite_destroy); + if (suite == NULL) { + fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE); + return; + } + CU_add_test(suite, "tracefs_iterate_raw_events API", + test_iter_raw_events); +} -- 2.24.1
![]() |