diff --git a/.gitmodules b/.gitmodules index da1e549..2d19dd6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,8 @@ -[submodule "test/lib/KUnity"] - path = test/lib/KUnity - url = gitlab@git.stubbe.rocks:kttd/KUnity-Core.git +[submodule "dev-utility/CMake-Module/BuildKernelModule"] + path = dev-utility/CMake-Module/BuildKernelModule + url = ../CMake-Module-KernelModuleBuilder.git + branch = master +[submodule "lib/KUnity"] + path = lib/KUnity + url = ../KUnity-Core.git + branch = master diff --git a/CMakeLists.txt b/CMakeLists.txt index 33c9a24..9733db9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,41 +1,37 @@ cmake_minimum_required(VERSION 2.6) -include("test/lib/KUnity/dev-utility/BuildKernelModule.cmake") +include("dev-utility/CMake-Module/BuildKernelModule/BuildKernelModule.cmake") SET(module_name kunity_test_runner_module) project (${module_name}) +if(NOT KERNEL_DIR) Set(KERNEL_DIR "/lib/modules/${CMAKE_SYSTEM_VERSION}/build" ) +endif() + set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -pedantic -Weverything") -file(GLOB module_src_files - "${PROJECT_SOURCE_DIR}/src/*.h" - "${PROJECT_SOURCE_DIR}/src/*.c") +file(GLOB module_src_files "${PROJECT_SOURCE_DIR}/src/*.c") -set(modules_includes - "${KERNEL_DIR}/include" "${PROJECT_SOURCE_DIR}/src" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/src") -add_module("${module_name}" "${module_src_files}" "${modules_includes}" "" "${KERNEL_DIR}") +include_directories( + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/lib/KUnity/src") +add_module("${module_name}" "${module_src_files}" "${KERNEL_DIR}") + +if(BUILD_TEST_MOUDLE) ## test module section + Set(TEST_MODULE_SOURCE_DIR "${PROJECT_BINARY_DIR}/test_${module_name}") -Set(TEST_MODULE_SOURCE_DIR "${PROJECT_BINARY_DIR}/test_${module_name}") + file(GLOB module_test_files + ${module_src_files} + "${PROJECT_SOURCE_DIR}/test/src/*.c" + "${PROJECT_SOURCE_DIR}/lib/KUnity/src/*.c" + "${PROJECT_SOURCE_DIR}/lib/KUnity/lib/Unity/src/*.c") -file(GLOB module_test_files - ${module_src_files} - "${PROJECT_SOURCE_DIR}/test/src/*.c" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/Kbuild" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/src/*.h" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/src/*.c" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/lib/fff/fff.h" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/lib/Unity/src/*.h" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/lib/Unity/src/*.c") + include_directories( + "${PROJECT_SOURCE_DIR}/test/src" + "${PROJECT_SOURCE_DIR}/lib/KUnity/lib/Unity/src") -file(GLOB test_modules_includes - ${modules_includes} - "${PROJECT_SOURCE_DIR}/test/src" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/src" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/lib/fff" - "${PROJECT_SOURCE_DIR}/test/lib/KUnity/lib/Unity/src") - -set(test_modules_definitions -DUNITY_INCLUDE_CONFIG_H) -add_module("test_${module_name}" "${module_test_files}" "${test_modules_includes}" "${test_modules_definitions}" "${KERNEL_DIR}") + add_definitions(-DUNITY_INCLUDE_CONFIG_H) + add_module("test_${module_name}" "${module_test_files}" "${KERNEL_DIR}") +endif() diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..af1eeca --- /dev/null +++ b/Kbuild @@ -0,0 +1,7 @@ +obj-m += kunity_test_runner_module.o +kunity_test_runner_module-objs += src/kunity_proc_test_file_handler.o +kunity_test_runner_module-objs += src/kunity_test_finder.o +kunity_test_runner_module-objs += src/runner_module.o + +ccflags-y += -I${PWD}/src +ccflags-y += -I${PWD}/lib/KUnity/src diff --git a/README.md b/README.md new file mode 100644 index 0000000..12c50be --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ + +# Kunity test runner module + +Is a runner module for runnig kunity test cases (see xxx). The module search for test function in the symbol table and made the them executionable byy uspase (via proc file) + + +## proc file struce + +* /proc/kunity_test + * -folder + * -file -> read of this file, will be run all test case of this module + * single_tests + * test_name-file -> read of this file, will be run the specific test case + +## building module + +### cmake + +``` bash +mkdir build +cd build +cmake ../ +# cmake -DKERNEL_DIR=/build M=${PWD} modules KBUILD_EXTRA_SYMBOLS=${PWD}/Module.symvers +#load module by "insmod kunity_test_runner_module.ko" +``` + +## execution + +simple use cat on the proc file :) + + +## module parameter + + * proc_test_root_folder_name = The name of the proc folder, which will contains the test proc files. (Default is "kunity_test") + * test_function_filter =a filter option for test function names, which the runner is looking for. (Default is "kunity_test_*") + * module_filter = a filter option for modules, which the runner is looking for test functions. (Default is * -> search in all modules) diff --git a/dev-utility/CMake-Module/BuildKernelModule b/dev-utility/CMake-Module/BuildKernelModule new file mode 160000 index 0000000..d30bc0c --- /dev/null +++ b/dev-utility/CMake-Module/BuildKernelModule @@ -0,0 +1 @@ +Subproject commit d30bc0c012a92c5ab1a6100d921e7a368b0763b8 diff --git a/dev-utility/build_envs/min-build.nix b/dev-utility/build_envs/min-build.nix new file mode 100644 index 0000000..dfcf403 --- /dev/null +++ b/dev-utility/build_envs/min-build.nix @@ -0,0 +1,15 @@ +with import {}; + +stdenv.mkDerivation rec { + name = "kttd-buid-env"; + env = buildEnv { name = name; paths = buildInputs; }; + + buildInputs = [ + gcc + cmake + elfutils + ]; + + hardeningDisable = [ "pic" ]; +} + diff --git a/lib/KUnity b/lib/KUnity new file mode 160000 index 0000000..82048f4 --- /dev/null +++ b/lib/KUnity @@ -0,0 +1 @@ +Subproject commit 82048f400e684eb87d8972db7469adc305c81d19 diff --git a/src/kunity_proc_test_file_handler.c b/src/kunity_proc_test_file_handler.c new file mode 100644 index 0000000..f028afc --- /dev/null +++ b/src/kunity_proc_test_file_handler.c @@ -0,0 +1,142 @@ +#include "kunity_proc_test_file_handler.h" +//{ global include region + +#include +#include +#include +#include +#include +#include +#include + +//} + +//{ local function prototypes region + +static int proc_test_file_open(/* in */ struct inode* inode, /* in */ struct file* file); + +static int proc_test_file_show(/* in */ struct seq_file* m, /* in */ void* v); + +static int proc_test_module_open(/* in */ struct inode* inode, /* in */ struct file* file); + +static int proc_test_module_show(/* in */ struct seq_file* m, /* in */ void* v); + +static void put_seq_char(/* in */ char letter); + +//} + +//{ local variables region + +static const struct file_operations proc_test_file_ops = { + .owner = THIS_MODULE, + .open = proc_test_file_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_test_module_ops = { + .owner = THIS_MODULE, + .open = proc_test_module_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct seq_file* test_proc_file; + +//} + +//{ global function implements region + +result_code_e create_proc_test_structure(/* in */ struct proc_dir_entry* parent, /* in */ const ptr_test_list_s test_list) +{ + ptr_test_module_list_item_s module = NULL; + result_code_e result = OK; + if (test_list == NULL) { + return ERROR_NULL_ARGUMENT; + } + + list_for_each_entry(module, &test_list->test_module_list, test_module_head) + { + ptr_test_list_item_s test_item = NULL; + const char* module_name = module == NULL ? "__KERNEL__" : module->test_module->name; + struct proc_dir_entry* module_folder = proc_mkdir(module_name, parent); + struct proc_dir_entry* single_test_folder = proc_mkdir("single_tests", module_folder); + struct proc_dir_entry* tmp_entry = proc_create_data(module_name, 0, module_folder, &proc_test_module_ops, module); + if (tmp_entry == NULL) { + return ERROR_INVALID_OPERATION; + } + + list_for_each_entry(test_item, &module->test_list, test_head) + { + tmp_entry = proc_create_data(test_item->test->name, 0, single_test_folder, &proc_test_file_ops, test_item->test); + if (tmp_entry == NULL) { + return ERROR_INVALID_OPERATION + 1; + } + } + } + + return result; +} + +//} + +//{ local function implements region + +static void put_seq_char(/* in */ char letter) +{ + seq_putc(test_proc_file, letter); +} + +static int proc_test_file_open(/* in */ struct inode* inode, /* in */ struct file* file) +{ + return single_open(file, proc_test_file_show, NULL); +} + +static int proc_test_module_open(/* in */ struct inode* inode, /* in */ struct file* file) +{ + return single_open(file, proc_test_module_show, NULL); +} + +static int proc_test_file_show(/* in */ struct seq_file* seqfile, /* in */ void* data) +{ + test_session_control_block_s output = { put_seq_char, 0, 0 }; + ptr_test_s tmp_test = PDE_DATA(file_inode(seqfile->file)); + if (tmp_test == NULL) { + return ERROR_INVALID_ARGUMENT; + } + + test_proc_file = seqfile; + return tmp_test->test_function(&output); +} + +static int proc_test_module_show(/* in */ struct seq_file* seqfile, /* in */ void* data) +{ + test_session_control_block_s output = { put_seq_char, 0, 1 }; + ptr_test_list_item_s tmp_test = NULL; + ptr_test_module_list_item_s tmp_module = PDE_DATA(file_inode(seqfile->file)); + if (tmp_module == NULL) { + return ERROR_INVALID_ARGUMENT; + } + + test_proc_file = seqfile; + list_for_each_entry(tmp_test, &tmp_module->test_list, test_head) + { + result_code_e result = OK; + if (list_is_last(&tmp_test->test_head, &tmp_module->test_list)) { + output._skip_end = 0; + } + + result = tmp_test->test->test_function(&output); + if (result != OK) { + return result; + } + + output._skip_start = 1; + } + + return OK; +} + +//} diff --git a/src/kunity_proc_test_file_handler.h b/src/kunity_proc_test_file_handler.h new file mode 100644 index 0000000..e487dc5 --- /dev/null +++ b/src/kunity_proc_test_file_handler.h @@ -0,0 +1,21 @@ +#ifndef KUNITY_PROC_TEST_FILE_HANDLER_H +#define KUNITY_PROC_TEST_FILE_HANDLER_H + +//{ global include region + +#include + +//} +//{ local include region + +#include "kunity_test_finder_t.h" + +//} + +//{ function region + +extern result_code_e create_proc_test_structure(/* in */ struct proc_dir_entry* parent, /* in */ const ptr_test_list_s test_list); + +//} + +#endif // KUNITY_PROC_TEST_FILE_HANDLER_H diff --git a/src/kunity_test_finder.c b/src/kunity_test_finder.c index b94c744..5625ab4 100644 --- a/src/kunity_test_finder.c +++ b/src/kunity_test_finder.c @@ -9,65 +9,39 @@ //} -//{ local include region +//{ local function prototypes region + +static result_code_e create_test(/* in */ const char* name, /* in */ const char* module_name, /* in */ const kunity_test_function_ptr test_function, /* out */ ptr_test_s* test_location); + +static result_code_e create_test_list_item(/* in */ const ptr_test_s test, /* out */ ptr_test_list_item_s* test_list_item_location); + +static result_code_e create_test_list(/* out */ ptr_test_list_s* test_list_location); + +static result_code_e create_test_module_list_item(/* in */ const struct module* module, /* out */ ptr_test_module_list_item_s* test_module_list_item_location); + +static result_code_e destroy_test(/* in */ ptr_test_s* test_location); + +static result_code_e destroy_test_list_item(/* in */ const ptr_test_list_item_s test_list_item); + +static result_code_e destroy_test_module(/* in */ const ptr_test_module_list_item_s test_module_item); + +static result_code_e add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_list_s test_list, /* in */ struct module* module); + +static int find_test_for_each(/* in */ void* data, /* in */ const char* namebuf, /* in */ struct module* module, /* in */ unsigned long address); + +static result_code_e _add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_module_list_item_s test_module); //} +//{ local variables region -//{ local define region +static const size_t sizeof_test = sizeof(test_s); -//} +static const size_t sizeof_test_list_item = sizeof(test_list_item_s); +static const size_t sizeof_test_module_list_item = sizeof(test_module_list_item_s); -//{ local enum region - -//} - - -//{ local typedef region - -//} - - -//{local struct region - -#pragma pack(push, 1) - -#pragma pack(pop) - -//} - - -//{ local function prototype region - -static result_code_e create_test(/* in */ const char * name, /* in */ const char * module_name, /* in */ const test_function_ptr test_function, /* out */ ptr_test_s * test_location); - -static result_code_e create_test_list_item(/* in */ const ptr_test_s test, /* out */ ptr_test_list_item_s * test_list_item_location); - -static result_code_e create_test_list(/* out */ ptr_test_list_s * test_list_location); - -static result_code_e destroy_test(/* in */ ptr_test_s * test_location); - -static result_code_e destroy_test_list_item(/* in */ ptr_test_list_item_s * test_list_item_location, /* out */ ptr_test_list_item_s * next_test_item_location); - -static result_code_e add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_list_s test_list); - -static int find_test_for_each(void *data, const char *namebuf, struct module *module, unsigned long address); - -//} - -//{ global variabel implements region - -//} - - -//{ local variabel implements region - -static const size_t sizeof_test = sizeof (test_s); - -static const size_t sizeof_test_list_item = sizeof (test_list_item_s); - -static const size_t sizeof_test_list = sizeof (test_list_s); +static const size_t sizeof_test_list = sizeof(test_list_s); //} @@ -75,213 +49,248 @@ static const size_t sizeof_test_list = sizeof (test_list_s); result_code_e find_tests(/* in */ const ptr_test_query_s query) { - if (query == NULL) - { - return ERROR_NULL_ARGUMENT; + if (query == NULL) { + return ERROR_NULL_ARGUMENT; } - if (create_test_list(&query->result_list) != OK) - { + if (create_test_list(&query->result_list) != OK) { return ERROR_INVALID_ARGUMENT; } - if(kallsyms_on_each_symbol(find_test_for_each, query) != 0) - { + if (kallsyms_on_each_symbol(find_test_for_each, query) != 0) { destroy_test_list(&query->result_list); return ERROR_INVALID_OPERATION; } return OK; } -//} +//} //{ local function implements region -static result_code_e create_test(/* in */ const char * name, /* in */ const char * module_name, /* in */ const test_function_ptr test_function, /* out */ ptr_test_s * test_location) +static result_code_e create_test(/* in */ const char* name, /* in */ const char* module_name, /* in */ const kunity_test_function_ptr test_function, /* out */ ptr_test_s* test_location) { ptr_test_s tmp_test = NULL; - if (name == NULL || module_name == NULL || test_function == NULL || test_location == NULL) - { - return ERROR_NULL_ARGUMENT; + if (name == NULL || module_name == NULL || test_function == NULL || test_location == NULL) { + return ERROR_NULL_ARGUMENT; } - if (*test_location != NULL) - { + if (*test_location != NULL) { return ERROR_INVALID_ARGUMENT; } - tmp_test = kmalloc(sizeof_test, GFP_KERNEL); - if (tmp_test == NULL) - { + tmp_test = kmalloc(sizeof_test, GFP_KERNEL); + if (tmp_test == NULL) { return ERROR_INVALID_OPERATION; } tmp_test->name = name; - tmp_test->modul_name = name; tmp_test->test_function = test_function; *test_location = tmp_test; return OK; } -static result_code_e create_test_list_item(/* in */ const ptr_test_s test, /* out */ ptr_test_list_item_s * test_list_item_location) +static result_code_e create_test_list_item(/* in */ const ptr_test_s test, /* out */ ptr_test_list_item_s* test_list_item_location) { ptr_test_list_item_s tmp_test_item = NULL; - if (test == NULL || test_list_item_location == NULL) - { - return ERROR_NULL_ARGUMENT; + if (test == NULL || test_list_item_location == NULL) { + return ERROR_NULL_ARGUMENT; } - if (*test_list_item_location != NULL) - { + if (*test_list_item_location != NULL) { return ERROR_INVALID_ARGUMENT; } tmp_test_item = kmalloc(sizeof_test_list_item, GFP_KERNEL); - if (tmp_test_item == NULL) - { + if (tmp_test_item == NULL) { return ERROR_INVALID_OPERATION; } tmp_test_item->test = test; - tmp_test_item->next = NULL; + INIT_LIST_HEAD(&tmp_test_item->test_head); *test_list_item_location = tmp_test_item; return OK; } -static result_code_e create_test_list(/* out */ ptr_test_list_s * test_list_location) +static result_code_e create_test_module_list_item(/* in */ const struct module* module, /* out */ ptr_test_module_list_item_s* test_module_list_item_location) { - ptr_test_list_s tmp_list = NULL; - if (test_list_location == NULL) - { - return ERROR_NULL_ARGUMENT; + ptr_test_module_list_item_s tmp_test_module_item = NULL; + if (test_module_list_item_location == NULL) { + return ERROR_NULL_ARGUMENT; } - if (*test_list_location != NULL) - { + if (*test_module_list_item_location != NULL) { + return ERROR_INVALID_ARGUMENT; + } + + tmp_test_module_item = kmalloc(sizeof_test_module_list_item, GFP_KERNEL); + if (tmp_test_module_item == NULL) { + return ERROR_INVALID_OPERATION; + } + + tmp_test_module_item->test_module = module; + INIT_LIST_HEAD(&tmp_test_module_item->test_module_head); + INIT_LIST_HEAD(&tmp_test_module_item->test_list); + *test_module_list_item_location = tmp_test_module_item; + return OK; +} + +static result_code_e create_test_list(/* out */ ptr_test_list_s* test_list_location) +{ + ptr_test_list_s tmp_list = NULL; + if (test_list_location == NULL) { + return ERROR_NULL_ARGUMENT; + } + + if (*test_list_location != NULL) { return ERROR_INVALID_ARGUMENT; } tmp_list = kmalloc(sizeof_test_list, GFP_KERNEL); - if (tmp_list == NULL) - { + if (tmp_list == NULL) { return ERROR_INVALID_OPERATION; } + INIT_LIST_HEAD(&tmp_list->test_module_list); + *test_list_location = tmp_list; return OK; } -static result_code_e destroy_test(/* in */ ptr_test_s * test_location) +static result_code_e destroy_test(/* in */ ptr_test_s* test_location) { - if (test_location == NULL || *test_location == NULL) - { + if (test_location == NULL || *test_location == NULL) { return ERROR_NULL_ARGUMENT; } - kfree(*test_location); + kzfree(*test_location); *test_location = NULL; return OK; } -static result_code_e destroy_test_list_item(/* in */ ptr_test_list_item_s * test_list_item_location, /* out */ ptr_test_list_item_s * next_test_item_location) +static result_code_e destroy_test_list_item(/* in */ const ptr_test_list_item_s test_list_item) { - ptr_test_list_item_s tmp_list_item = NULL; - if (test_list_item_location == NULL || *test_list_item_location == NULL) - { + if (test_list_item == NULL) { return ERROR_NULL_ARGUMENT; } - tmp_list_item = *test_list_item_location; - if (next_test_item_location != NULL) - { - *next_test_item_location = tmp_list_item->next; - } - - destroy_test(&tmp_list_item->test); - kfree(tmp_list_item); - *test_list_item_location = NULL; + destroy_test(&test_list_item->test); + kzfree(test_list_item); return OK; } -result_code_e destroy_test_list(/* in */ ptr_test_list_s * test_list_location) +result_code_e destroy_test_list(/* in */ ptr_test_list_s* test_list_location) { + ptr_test_list_s tmp_list = NULL; - ptr_test_list_item_s tmp_test_item = NULL; - if (test_list_location == NULL || *test_list_location == NULL) - { + if (test_list_location == NULL || *test_list_location == NULL) { return ERROR_NULL_ARGUMENT; } tmp_list = *test_list_location; - tmp_test_item = tmp_list->head; - while (tmp_test_item != NULL) - { - ptr_test_list_item_s tmp_next_test_item = NULL; - if (destroy_test_list_item(&tmp_test_item, &tmp_next_test_item) != OK) - { - break; + while (!list_empty(&tmp_list->test_module_list)) { + result_code_e result = OK; + ptr_test_module_list_item_s module = list_entry(tmp_list->test_module_list.next, test_module_list_item_s, test_module_head); + list_del(&module->test_module_head); + result = destroy_test_module(module); + if (result != OK) { + return result; } - - tmp_test_item = tmp_next_test_item; } - kfree(tmp_list); + kzfree(tmp_list); *test_list_location = NULL; return OK; } -static result_code_e add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_list_s test_list) +static result_code_e _add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_module_list_item_s test_module) { - if(test_item == NULL || test_list == NULL) - { - return ERROR_NULL_ARGUMENT; + if (test_item == NULL || test_module == NULL) { + return ERROR_NULL_ARGUMENT; } - test_list->count++; - test_item->next = test_list->head; - test_list->head = test_item; + list_add(&test_item->test_head, &test_module->test_list); return OK; } -static int find_test_for_each(void *data, const char *namebuf, struct module *module, unsigned long address) +static result_code_e add_test_list_item(/* in */ ptr_test_list_item_s test_item, /* in */ ptr_test_list_s test_list, /* in */ struct module* module) +{ + ptr_test_module_list_item_s it = NULL; + if (test_item == NULL || test_list == NULL) { + return ERROR_NULL_ARGUMENT; + } + + list_for_each_entry(it, &test_list->test_module_list, test_module_head) + { + if (it->test_module != module) { + continue; + } + + return _add_test_list_item(test_item, it); + } + + it = NULL; + if (create_test_module_list_item(module, &it) != OK) { + return ERROR_INVALID_OPERATION; + } + + list_add(&it->test_module_head, &test_list->test_module_list); + return _add_test_list_item(test_item, it); +} + +static int find_test_for_each(/* in */ void* data, /* in */ const char* namebuf, /* in */ struct module* module, /* in */ unsigned long address) { ptr_test_query_s query = NULL; ptr_test_s test = NULL; ptr_test_list_item_s test_item = NULL; - const char * module_name= module == NULL ? "__KERNEL__" : module->name; - if (address ==0) - { + const char* module_name = module == NULL ? "__KERNEL__" : module->name; + if (address == 0) { return 0; } query = (ptr_test_query_s)data; - if (glob_match(query->module_filter, module_name) == 0) - { + if (glob_match(query->module_filter, module_name) == 0) { return 0; } - if (glob_match(query->test_function_filter, namebuf) == 0) - { + if (glob_match(query->test_function_filter, namebuf) == 0) { return 0; } - if (create_test(namebuf, module_name, (test_function_ptr)address, &test) != OK) - { + if (create_test(namebuf, module_name, (kunity_test_function_ptr)address, &test) != OK) { return 0; } - if (create_test_list_item(test, &test_item) != OK) - { + if (create_test_list_item(test, &test_item) != OK) { destroy_test(&test); return 0; } - if (add_test_list_item(test_item, query->result_list) != OK) - { - destroy_test_list_item(&test_item, NULL); + if (add_test_list_item(test_item, query->result_list, module) != OK) { + destroy_test_list_item(test_item); } return 0; } +static result_code_e destroy_test_module(/* in */ const ptr_test_module_list_item_s test_module_item) +{ + + if (test_module_item == NULL) { + return ERROR_NULL_ARGUMENT; + } + + while (!list_empty(&test_module_item->test_list)) { + result_code_e result = OK; + ptr_test_list_item_s test_item = list_entry(test_module_item->test_list.next, test_list_item_s, test_head); + list_del(&test_item->test_head); + result = destroy_test_list_item(test_item); + if (result != OK) { + return result; + } + } + + kzfree(test_module_item); + return OK; +} //} diff --git a/src/kunity_test_finder.h b/src/kunity_test_finder.h index aa71f1a..e99b40d 100644 --- a/src/kunity_test_finder.h +++ b/src/kunity_test_finder.h @@ -1,26 +1,13 @@ #ifndef KUNITY_TEST_FINDER_H #define KUNITY_TEST_FINDER_H #include "kunity_test_finder_t.h" -//{ global include region - -//} -//{ local include region - -//} - -#ifdef __cplusplus -extern "C" { -#endif //{ function region extern result_code_e find_tests(/* in */ const ptr_test_query_s query); -extern result_code_e destroy_test_list(/* in */ ptr_test_list_s * test_list_location); +extern result_code_e destroy_test_list(/* in */ ptr_test_list_s* test_list_location); //} -#ifdef __cplusplus -} -#endif #endif // KUNITY_TEST_FINDER_H diff --git a/src/kunity_test_finder_t.h b/src/kunity_test_finder_t.h index 2d45f9d..06663f6 100644 --- a/src/kunity_test_finder_t.h +++ b/src/kunity_test_finder_t.h @@ -3,37 +3,23 @@ //{ global include region +#include +#include +#include #include //} -//{ local include region - -//} - - //{ define region +#ifndef KUNITY_DEFAULT_TEST_NAME_FITER +#define KUNITY_DEFAULT_TEST_NAME_FITER KUNITY_DEFAULT_TEST_NAME_PREFIX* +#endif -//} - - -//{ enum region - -typedef enum result_code_eTag -{ - OK, - ERROR_NULL_ARGUMENT, - ERROR_INVALID_ARGUMENT, - ERROR_INVALID_OPERATION -} result_code_e, *ptr_result_code_e; - -//} - - -//{ typedef region - -typedef void (*test_function_ptr) (void); - +#ifndef KUNITY_DEFAULT_TEST_NAME_FITER_STR +#define STR(s) #s +#define XSTR(s) STR(s) +#define KUNITY_DEFAULT_TEST_NAME_FITER_STR XSTR(KUNITY_DEFAULT_TEST_NAME_FITER) +#endif //} //{ struct region @@ -42,32 +28,31 @@ typedef void (*test_function_ptr) (void); #pragma pack(pop) -typedef struct test_sTag -{ - const char * name; - const char * modul_name; - test_function_ptr test_function; -} test_s, *ptr_test_s; - -typedef struct test_list_item_sTag -{ +typedef struct test_list_item_sTag { + struct list_head test_head; ptr_test_s test; - struct test_list_item_sTag * next; } test_list_item_s, *ptr_test_list_item_s; -typedef struct test_list_sTag -{ - size_t count; - ptr_test_list_item_s head; +typedef struct test_module_list_item_sTag { + struct list_head test_module_head; + const struct module* test_module; + struct list_head test_list; +} test_module_list_item_s, *ptr_test_module_list_item_s; + +typedef struct test_list_sTag { + struct list_head test_module_list; } test_list_s, *ptr_test_list_s; -typedef struct test_query_sTag -{ - const char * test_function_filter; - const char * module_filter; +typedef struct test_query_sTag { + const char* test_function_filter; + const char* module_filter; ptr_test_list_s result_list; } test_query_s, *ptr_test_query_s; +typedef result_code_e (*test_list_iterator)(/* in */ const ptr_test_list_item_s); + +typedef result_code_e (*test_module_list_iterator)(/* in */ const ptr_test_module_list_item_s); + //} #endif // KUNITY_TEST_FINDER_T_H diff --git a/src/runner_module.c b/src/runner_module.c index b4fae61..a35f06e 100644 --- a/src/runner_module.c +++ b/src/runner_module.c @@ -1,84 +1,141 @@ //{ global include region -#include #include +#include +#include +#include //} //{ local include region +#include "kunity_proc_test_file_handler.h" #include "kunity_test_finder.h" //} - -//{ local define region - -//} - - -//{ local enum region - -//} - - //{ local typedef region -//} - - -//{local struct region - -#pragma pack(push, 1) - -#pragma pack(pop) +typedef struct runner_control_block_sTag { + const char* proc_folder_name; + struct proc_dir_entry* proc_test_root; + test_query_s query; +} runner_control_block_s, *ptr_runner_control_blocks; //} -//{ local function prototype region +//{ local function prototypes region + +static void init_tests(/* in */ struct work_struct* work); + +static void clean_tests(void); static int kunity_init(void); + static void kunity_exit(void); //} -//{ global variabel implements region +//{ local variables region + +static struct workqueue_struct* queue; + +DECLARE_WORK(work, init_tests); + +static char* module_filter = "*"; +module_param(module_filter, charp, 0); +MODULE_PARM_DESC(module_filter, "a filter option for modules, which the runner is looking for test functions. (Default is \"*\""); + +static char* test_function_filter = KUNITY_DEFAULT_TEST_NAME_FITER_STR; +module_param(test_function_filter, charp, 0); +MODULE_PARM_DESC(test_function_filter, "a filter option for test function names, which the runner is looking for. (Default is \"kunity_test_*\""); + +static char* proc_test_root_folder_name = "kunity_test"; +module_param(proc_test_root_folder_name, charp, 0); +MODULE_PARM_DESC(proc_test_root_folder_name, "the name of the proc folder, which will contains the test proc files. (Default is \"kunity_test\""); + +static const size_t sizeof_runner_control_block = sizeof(runner_control_block_s); + +static runner_control_block_s* rcb = NULL; //} -//{ local variabel implements region - -static test_query_s query; - -//} - - -//{ global function implements region - -//} - - //{ local function implements region +static void clean_tests() +{ + destroy_test_list(&rcb->query.result_list); + if (rcb->proc_test_root != NULL) { + proc_remove(rcb->proc_test_root); + } + + kzfree(rcb); +} + +static void init_tests(/* in */ struct work_struct* work) +{ + result_code_e result = OK; + if (rcb != NULL) { + clean_tests(); + } + + rcb = kzalloc(sizeof(runner_control_block_s), GFP_KERNEL); + rcb->query.test_function_filter = test_function_filter; + rcb->query.module_filter = module_filter; + rcb->proc_folder_name = proc_test_root_folder_name; + rcb->proc_test_root = proc_mkdir(rcb->proc_folder_name, NULL); + if (rcb->proc_test_root == NULL) { + pr_warning("cant create proc folder %s", rcb->proc_folder_name); + return; + } + + result = find_tests(&rcb->query); + if (result == OK) { + result = create_proc_test_structure(rcb->proc_test_root, rcb->query.result_list); + if (result == OK) { + pr_info("successful created tests with following options:"); + } else { + pr_info("test creation failed with error code %u, following options was used:", result); + } + } else { + pr_info("could not find any test with follwing options:"); + } + + pr_info("\tmodule_filter = \"%s\"", rcb->query.module_filter); + pr_info("\ttest_function_filter = \"%s\"", rcb->query.test_function_filter); + pr_info("\tproc_folder_name = \"%s\"", rcb->proc_folder_name); +} + static int kunity_init() { - pr_info("init kunity_test_runner_module"); - find_tests(&query); - return 0; + pr_info("init %s", THIS_MODULE->name); + queue = create_workqueue("test_runner_work_queue"); + if (queue == NULL) { + return -ERROR_INVALID_OPERATION; + } + + return !queue_work(queue, &work); } static void kunity_exit() { - pr_info("init kunity_test_runner_module"); - destroy_test_list(&query.result_list); + pr_info("exit %s", THIS_MODULE->name); + if (queue == NULL) { + return; + } + + destroy_workqueue(queue); + if (rcb == NULL) { + return; + } + + clean_tests(); } //} - -module_init(kunity_init) -module_exit(kunity_exit) - +module_init(kunity_init); +module_exit(kunity_exit); MODULE_AUTHOR("Felix Stubbe"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("run tests"); +MODULE_DESCRIPTION("run kunity tests"); diff --git a/test/lib/KUnity b/test/lib/KUnity deleted file mode 160000 index 09b8930..0000000 --- a/test/lib/KUnity +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 09b89307c8400f9dbe8e1e5ad2a6787a71c69fdb diff --git a/test/src/kunity_proc_test_file_handler_tests.c b/test/src/kunity_proc_test_file_handler_tests.c new file mode 100644 index 0000000..ba32960 --- /dev/null +++ b/test/src/kunity_proc_test_file_handler_tests.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + + +//extern result_code_e kunity_module_runner_fake_test_function_ok(const ptr_output_functions_s output); + +KUNITY_TEST(create_proc_test_file_null_argument) +{ + TEST_ASSERT_EQUAL(ERROR_NULL_ARGUMENT, create_proc_test_structure(NULL,NULL)); +} + + +KUNITY_TEST(create_proc_test_file_ok) +{ + test_s test; + + test_list_s list; + test_module_list_item_s module_item; + test_list_item_s test_item; + struct proc_dir_entry* test_root = proc_mkdir("test_kunity_test_root", NULL); + module_item.test_module = THIS_MODULE; + INIT_LIST_HEAD(&test_item.test_head); + INIT_LIST_HEAD(&list.test_module_list); + INIT_LIST_HEAD(&module_item.test_module_head); + INIT_LIST_HEAD(&module_item.test_list); + list_add(&test_item.test_head, &module_item.test_list); + list_add(&module_item.test_module_head, &list.test_module_list); + test.name = "fake_test_function"; + test.test_function = NULL; + test_item.test = &test; + if (test_root == NULL) { + TEST_FAIL_MESSAGE("could not create \"test_kunity_test_root proc\" folder"); + } + + TEST_ASSERT_EQUAL(OK, create_proc_test_structure(test_root, &list)); + proc_remove(test_root); +} diff --git a/test/src/kunity_test_finder_tests.c b/test/src/kunity_test_finder_tests.c new file mode 100644 index 0000000..0ada885 --- /dev/null +++ b/test/src/kunity_test_finder_tests.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + + +result_code_e kunity_module_runner_fake_test_function_ok(const ptr_test_session_control_block_s output) +{ + return OK; +} +EXPORT_SYMBOL(kunity_module_runner_fake_test_function_ok); + +static size_t tmp_list_counter; +static result_code_e assert_test_item(/* in */ const ptr_test_list_item_s test_list_item) +{ + TEST_ASSERT_NOT_EQUAL(NULL, test_list_item); + TEST_ASSERT_NOT_EQUAL(NULL, test_list_item->test); + TEST_ASSERT_NOT_EQUAL(NULL, test_list_item->test->name); + TEST_ASSERT_NOT_EQUAL(NULL, test_list_item->test->test_function); + tmp_list_counter++; + return OK; +} + + +KUNITY_TEST(test_find_test_null_argument) +{ + TEST_ASSERT_EQUAL(ERROR_NULL_ARGUMENT, find_tests(NULL)); +} + +KUNITY_TEST(test_find_test_invalid_argument) +{ + test_list_s list; + test_query_s query ={ KUNITY_DEFAULT_TEST_NAME_FITER_STR, "*", &list}; + + TEST_ASSERT_EQUAL(ERROR_INVALID_ARGUMENT, find_tests(&query)); +} + +KUNITY_TEST(test_find_test_found) +{ + ptr_test_module_list_item_s module = NULL; + ptr_test_list_item_s test = NULL; + test_query_s query ={ "kunity_module_runner_fake_test_function_ok", THIS_MODULE->name, NULL}; + TEST_ASSERT_EQUAL(OK, find_tests(&query)); + TEST_ASSERT_NOT_NULL(query.result_list); + + module = list_first_entry(&query.result_list->test_module_list, test_module_list_item_s, test_module_head); + TEST_ASSERT_NOT_NULL(module); + test = list_first_entry(&module->test_list, test_list_item_s, test_head); + TEST_ASSERT_NOT_NULL(test); + TEST_ASSERT_EQUAL_STRING("kunity_module_runner_fake_test_function_ok", test->test->name); + TEST_ASSERT_EQUAL_PTR(&kunity_module_runner_fake_test_function_ok, test->test->test_function); +} + + +KUNITY_TEST(test_find_tests_found) +{ + ptr_test_module_list_item_s module = NULL; + ptr_test_list_item_s test = NULL; + test_query_s query ={ KUNITY_DEFAULT_TEST_NAME_FITER_STR, "*", NULL}; + TEST_ASSERT_EQUAL(OK, find_tests(&query)); + TEST_ASSERT_NOT_NULL (query.result_list); + TEST_ASSERT_FALSE( list_empty(&query.result_list->test_module_list)) + module = list_first_entry(&query.result_list->test_module_list, test_module_list_item_s, test_module_head); + TEST_ASSERT_FALSE( list_empty(&module->test_list)) + tmp_list_counter = 0; + list_for_each_entry(test, &module->test_list, test_head) + { + assert_test_item(test); + } + + TEST_ASSERT_GREATER_OR_EQUAL(1, tmp_list_counter); +} + + diff --git a/test/src/test.c b/test/src/test.c deleted file mode 100644 index fb4be80..0000000 --- a/test/src/test.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -DEFINE_FFF_GLOBALS - -FAKE_VOID_FUNC(IO_MEM_WR8, int, int); - - -KUNITY_TEST(bar_test) -{ - IO_MEM_WR8(1,0); - TEST_ASSERT_EQUAL_INT(1, IO_MEM_WR8_fake.call_count); - TEST_ASSERT_TRUE(1) -} - - -void bar_test_2(void) -{ - kunity_test_bar_test(); - pr_info ("huhu"); -}