diff options
| author | 陆秋文 <[email protected]> | 2024-07-15 09:48:50 +0000 |
|---|---|---|
| committer | 陆秋文 <[email protected]> | 2024-07-15 09:48:50 +0000 |
| commit | f0e50964001c56042150c9c49284bf0aaa531a7c (patch) | |
| tree | dd15b7248485ecade179524a7670630f21be68ff /app | |
| parent | 24f4ab0940ef3652908b3a5968527951c53f66b8 (diff) | |
Feature mock api by cmocka
Diffstat (limited to 'app')
| -rw-r--r-- | app/CMakeLists.txt | 47 | ||||
| -rw-r--r-- | app/include/mrapp.h | 3 | ||||
| -rw-r--r-- | app/src/dp_trace.c | 9 | ||||
| -rw-r--r-- | app/src/marsio.c | 82 | ||||
| -rw-r--r-- | app/src/mrb.c | 1 | ||||
| -rw-r--r-- | app/src/rawio.c | 4 | ||||
| -rw-r--r-- | app/test/test_marsio_instance_api.c | 356 | ||||
| -rw-r--r-- | app/test/test_marsio_rawio_api.c | 509 |
8 files changed, 982 insertions, 29 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3941080..6bdb576 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,6 +1,6 @@ find_package(SYSTEMD REQUIRED) include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_SOURCE_DIR}/include/extern) +include_directories(${CMAKE_SOURCE_DIR}/include/external) include_directories(${CMAKE_SOURCE_DIR}/include/internal) include_directories(include) @@ -18,3 +18,48 @@ target_include_directories(marsio INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include target_include_directories(marsio INTERFACE ${SYSTEMD_INCLUDE_DIRS}) install(TARGETS marsio LIBRARY DESTINATION ${MR_INSTALL_LIBDIR} COMPONENT Program) + + +################################################################################ +### unittests ################################################################## + +add_executable(test_marsio_rawio_api test/test_marsio_rawio_api.c src/marsio.c src/rawio.c src/mrb.c + src/sendpath.c src/monit.c src/tap.c src/dp_trace.c) + +target_link_libraries(test_marsio_rawio_api libcmocka libdpdk pthread infra elf z dl rt MESA_prof_load_static MESA_htable_static) + +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/include/external) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/include/internal) +target_include_directories(test_marsio_rawio_api PRIVATE ${CMAKE_SOURCE_DIR}/infra/include) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_enqueue_bulk) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_dequeue_burst) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_rt_object_retrieve) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_open_device) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_close_device) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_free_v2) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_dp_trace_measurements_can_emit) +target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_do_rehash) + +add_test(NAME test_marsio_rawio_api COMMAND test_marsio_rawio_api) + +################################################################################ +add_executable(test_marsio_instance_api test/test_marsio_instance_api.c src/marsio.c src/rawio.c src/mrb.c + src/sendpath.c src/monit.c src/tap.c src/dp_trace.c) + +target_link_libraries(test_marsio_instance_api libcmocka libdpdk pthread infra elf z dl rt MESA_prof_load_static MESA_htable_static) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/include/external) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/include/internal) +target_include_directories(test_marsio_instance_api PRIVATE ${CMAKE_SOURCE_DIR}/infra/include) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_eal_init) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_exit) +target_link_libraries(test_marsio_instance_api -Wl,--wrap=rte_mp_request_sync) + +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_dequeue_burst) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=vnode_mirror_rt_object_retrieve) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_open_device) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_close_device) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_free_v2) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_dp_trace_measurements_can_emit) +#target_link_libraries(test_marsio_rawio_api -Wl,--wrap=marsio_buff_do_rehash)
\ No newline at end of file diff --git a/app/include/mrapp.h b/app/include/mrapp.h index 0ea11bb..a81285e 100644 --- a/app/include/mrapp.h +++ b/app/include/mrapp.h @@ -1,6 +1,4 @@ #pragma once - -#include "dp_trace.h" #include <common.h> #include <ldbc.h> #include <marsio.h> @@ -11,6 +9,7 @@ #include <vdev_define.h> struct mr_instance; +struct dp_trace_process; struct mrapp_stat { diff --git a/app/src/dp_trace.c b/app/src/dp_trace.c index 361da17..55911d7 100644 --- a/app/src/dp_trace.c +++ b/app/src/dp_trace.c @@ -12,6 +12,7 @@ #include <sys/stat.h> #include <sys/utsname.h> #include <unistd.h> +#include <dp_trace.h> extern __thread struct mr_thread_info thread_info; @@ -19,7 +20,10 @@ int marsio_dp_trace_init(struct mr_instance * mr_instance) { mr_instance->trace = dp_trace_process_create(DP_TRACE_PROCESS_APP); if (mr_instance->trace == NULL) + { return RT_ERR; + } + return RT_SUCCESS; } @@ -93,6 +97,11 @@ cJSON * marsio_dp_trace_monit_loop(struct mr_instance * instance) cJSON * json_root = cJSON_CreateObject(); struct dp_trace_process * trace = instance->trace; + if (trace == NULL) + { + return json_root; + } + struct dp_trace_stat monit_statistics = {}; uint64_t filter_exec_hit = 0; diff --git a/app/src/marsio.c b/app/src/marsio.c index f61d935..8ae6a35 100644 --- a/app/src/marsio.c +++ b/app/src/marsio.c @@ -153,13 +153,15 @@ static void mrapp_rx_notify_init(struct mr_instance * instance) } /* EAL环境初始化 */ -static void mrapp_eal_init(struct mr_instance * instance) +static int mrapp_eal_init(struct mr_instance * instance) { char * eal_argv[MR_LIB_MAX_EAL_ARGC]; unsigned int eal_argc = 0; if (g_eal_inited > 0) - return; + { + return 0; + } WRITE_ARG(instance->appsym); WRITE_ARG("-c"); @@ -167,8 +169,8 @@ static void mrapp_eal_init(struct mr_instance * instance) WRITE_ARG("--proc-type=secondary"); char str_virtaddr[MR_STRING_MAX]; - int ret = - MESA_load_profile_string_nodef(instance->g_cfgfile_path, "eal", "virtaddr", str_virtaddr, sizeof(str_virtaddr)); + int ret = MESA_load_profile_string_nodef(instance->g_cfgfile_path, "eal", "virtaddr", str_virtaddr, + sizeof(str_virtaddr)); if (ret >= 0) { @@ -224,20 +226,35 @@ static void mrapp_eal_init(struct mr_instance * instance) /* 获得当前线程的亲和性设置,EAL初始化后恢复,避免从此线程派生的 线程全部带有EAL设置的亲和性。 */ - cpu_set_t __cpu_set; - ret = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &__cpu_set); - MR_VERIFY_2(ret >= 0, "Cannot get init thread affinity: %s", strerror(errno)); + cpu_set_t _cpu_set; + ret = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cpu_set); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot get init thread affinity: %s", strerror(errno)); + goto errout; + } rte_openlog_stream(stderr); - ret = rte_eal_init(eal_argc, eal_argv); - MR_VERIFY_2(ret >= 0, "Cannot init EAL Enviorment, Failed"); + ret = rte_eal_init((int)eal_argc, eal_argv); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot init EAL environment, Failed."); + goto errout; + } - ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &__cpu_set); - MR_VERIFY_2(ret >= 0, "Cannot set init thread affinity: %s", strerror(errno)); + ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cpu_set); + if (unlikely(ret < 0)) + { + MR_ERROR("Cannot set init thread affinity: %s", strerror(errno)); + goto errout; + } /* EAL环境初始化成功 */ g_eal_inited = 1; - return; + return 0; + +errout: + return -1; } struct app_register_req * app_register_request_construct(struct mr_instance * instance) @@ -290,16 +307,15 @@ void * marsio_survival_monitor(void * arg) int send_register_request(struct app_register_req * reg_req) { - int ret; int socket_pair[2]; - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair); + int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair); if (ret < 0) { MR_WARNING("Failed to create socketpair"); return RT_ERR; } - struct rte_mp_reply mp_reply; + struct rte_mp_reply mp_reply = {}; const struct timespec wait_timespec = { .tv_nsec = 0, .tv_sec = 30, @@ -314,6 +330,7 @@ int send_register_request(struct app_register_req * reg_req) reg_msg.num_fds = 1; reg_msg.len_param = sizeof(ptr_address); memcpy(reg_msg.param, &ptr_address, sizeof(ptr_address)); + ret = rte_mp_request_sync(®_msg, &mp_reply, &wait_timespec); if (ret < 0) { @@ -335,6 +352,7 @@ int send_register_request(struct app_register_req * reg_req) // Make sure the socket_pair[0] of the main process is closed and the kernel sends EOF _current_instance->marsio_fd = socket_pair[1]; close(socket_pair[0]); + pthread_t __pid = 0; ret = pthread_create(&__pid, NULL, marsio_survival_monitor, NULL); if (ret < 0) @@ -343,15 +361,23 @@ int send_register_request(struct app_register_req * reg_req) goto error; } - free(mp_reply.msgs); - FREE(reg_req); - FREE(rep_msg); + if (mp_reply.msgs != NULL) + { + free(mp_reply.msgs); + } + + rte_free(reg_req); + rte_free(rep_msg); return RT_SUCCESS; error: - free(mp_reply.msgs); - FREE(reg_req); - FREE(rep_msg); + if (mp_reply.msgs != NULL) + { + free(mp_reply.msgs); + } + + rte_free(reg_req); + rte_free(rep_msg); close(socket_pair[0]); close(socket_pair[1]); return RT_ERR; @@ -737,13 +763,19 @@ int marsio_init(struct mr_instance * instance, const char * appsym) goto err; } - mrapp_eal_init(instance); + if (mrapp_eal_init(instance) != RT_SUCCESS) + { + MR_ERROR("EAL initialization failed, recheck mrzcpd is running."); + goto err; + } +#if 0 if (marsio_dp_trace_init(instance) != RT_SUCCESS) { MR_ERROR("data path instance get failed, recheck mrzcpd is running."); goto err; } +#endif if (mrapp_register(instance) != RT_SUCCESS) { @@ -776,7 +808,10 @@ int marsio_init(struct mr_instance * instance, const char * appsym) err: if (instance->is_exit_when_err_raise) + { exit(EXIT_FAILURE); + } + return RT_ERR; } @@ -833,7 +868,10 @@ int marsio_thread_init(struct mr_instance * instance) out: pthread_mutex_unlock(&instance->lock_thread_init); if (ret < 0 && instance->is_exit_when_err_raise) + { exit(EXIT_FAILURE); + } + return ret; } diff --git a/app/src/mrb.c b/app/src/mrb.c index fe2a3ea..ea852c3 100644 --- a/app/src/mrb.c +++ b/app/src/mrb.c @@ -5,6 +5,7 @@ #include <mrb_define.h> #include <mrdp_trace.h> #include <protect.h> +#include <dp_trace.h> #include <rte_common.h> #include <rte_malloc.h> diff --git a/app/src/rawio.c b/app/src/rawio.c index 427534c..b4f3bc4 100644 --- a/app/src/rawio.c +++ b/app/src/rawio.c @@ -57,7 +57,6 @@ int mrapp_packet_fast_send_burst(struct mr_instance * instance, struct vdev_inst int marsio_recv_burst(struct mr_vdev * vdev, queue_id_t qid, marsio_buff_t * mbufs[], int nr_mbufs) { - assert(qid < vdev->nr_rxstream); if (unlikely(qid >= vdev->nr_rxstream)) return -EINVAL; @@ -214,11 +213,8 @@ int marsio_send_burst_with_options(struct mr_sendpath * sendpath, queue_id_t sid struct rte_mbuf ** _mbufs = (struct rte_mbuf **)mbufs; PROTECT_rte_mbuf_unpoison_bulk(_mbufs, nr_mbufs); - assert(sid < sendpath->target_vdi->nr_txstream); - for (int i = 0; i < nr_mbufs; i++) { - assert(_mbufs[i]->data_len != 0 && _mbufs[i]->pkt_len != 0); __rte_mbuf_sanity_check(mbufs[i], i); } diff --git a/app/test/test_marsio_instance_api.c b/app/test/test_marsio_instance_api.c new file mode 100644 index 0000000..301507a --- /dev/null +++ b/app/test/test_marsio_instance_api.c @@ -0,0 +1,356 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <rte_mbuf.h> +#include <rte_mempool.h> +#include <rte_eal.h> +#include <cmocka.h> +#include <marsio.h> + +#include <mr_rte_msg.h> + +extern int __real_rte_eal_init(int argc, char **argv); + +int __wrap_rte_eal_init(int argc, char * argv[]) +{ + int inject_eal_init_failed = mock_type(int); + if (inject_eal_init_failed) + { + return -1; + } + + return 0; +} + +static int rte_exit_called = 0; +int __wrap_rte_exit(int status) +{ + rte_exit_called = 1; + return 0; +} + +static int call_real_rte_mp_request_sync = 1; +extern int __real_rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, + const struct timespec *ts); + +int __wrap_rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, + const struct timespec *ts) +{ + if (call_real_rte_mp_request_sync) + { + return __real_rte_mp_request_sync(req, reply, ts); + } + + int mock_ret = mock_type(int); + if (mock_ret != 0) + { + return mock_ret; + } + + struct rte_mp_msg * mock_out_req = mock_ptr_type(struct rte_mp_msg *); + if (strcasecmp(req->name, "instance_alive_register") == 0) + { + struct app_register_resp * mock_resp = rte_zmalloc(NULL, sizeof(struct app_register_resp), 0); + mock_resp->errcode = mock_type(int); + + const char * mock_symbol = mock_ptr_type(const char *); + const char * mock_strerr = mock_ptr_type(const char *); + + snprintf((char *)mock_resp->symbol, sizeof(mock_resp->symbol), "%s", mock_symbol); + snprintf((char *)mock_resp->strerr, sizeof(mock_resp->strerr), "%s", mock_strerr); + + /* NOTE: mock_msg_resp must alloc by malloc(), and release by free() */ + struct rte_mp_msg * mock_msg_resp = malloc(sizeof(struct rte_mp_msg)); + memset(mock_msg_resp, 0, sizeof(struct rte_mp_msg)); + + mock_msg_resp->len_param = sizeof(uintptr_t); + *(uintptr_t *)(&mock_msg_resp->param) = (uintptr_t)mock_resp; + + reply->msgs = mock_msg_resp; + } + else + { + assert(0); + } + + if (mock_out_req != NULL) + { + /* copy the param */ + memcpy(mock_out_req->param, req->param, req->len_param); + mock_out_req->len_param = req->len_param; + + /* copy the name */ + snprintf(mock_out_req->name, sizeof(mock_out_req->name), "%s", req->name); + + /* dup the fds */ + for (unsigned int i = 0; i < req->num_fds; i++) + { + mock_out_req->fds[i] = dup(req->fds[i]); + } + + mock_out_req->num_fds = req->num_fds; + } + + return mock_ret; +} + +const char * fake_mrmonit_daemon_text = "{\n" + " \"general\": {\n" + " \"unixtime\": 1718330269,\n" + " \"g_cfgfile\": \"/opt/mrzcpd/etc/mrglobal.conf\",\n" + " \"g_hwfile\": \"/var/run/mrzcpd/hwfile.json\"\n" + " }\n" + "}"; + +static void testcase_marsio_init_register_succ(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + mkdir("/var/run/mrzcpd", 0755); + + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + +#if 0 + will_return(__wrap_rte_eal_init, 0); +#endif + + struct rte_mp_msg msg_req; + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, &msg_req); + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, "test_marsio_init"); + will_return(__wrap_rte_mp_request_sync, "successful"); + + /* should success */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, 0); + + /* there's only one fd transfer to service process */ + assert_int_equal(msg_req.num_fds, 1); + + /* try to close the fd to simulate the service exit or crash */ + close(msg_req.fds[0]); + + /* sleep 1s, and the exit should be called */ + sleep(1); + + assert_int_equal(rte_exit_called, 1); + rte_exit_called = 0; + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_register_failed_by_errcode(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + +#if 0 + will_return(__wrap_rte_eal_init, 0); +#endif + + struct rte_mp_msg msg_req; + will_return(__wrap_rte_mp_request_sync, 0); + will_return(__wrap_rte_mp_request_sync, &msg_req); + will_return(__wrap_rte_mp_request_sync, 1); + will_return(__wrap_rte_mp_request_sync, "test_mrapp"); + will_return(__wrap_rte_mp_request_sync, "test_mrapp register failed"); + + /* should fail, as the mrapp register failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + + +static void testcase_marsio_int_register_failed_by_mp_sync_failed(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + mkdir("/var/run/mrzcpd", 0755); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + + will_return(__wrap_rte_eal_init, 0); + + /* inject the mrapp register failed, ret value and reply value */ + will_return(__wrap_rte_mp_request_sync, -1); + + /* should fail, as the mrapp register failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_eal_failed(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* create a service daemon monit file to simulate the service is running */ + FILE * fp = fopen("/var/run/mrzcpd/mrmonit.daemon", "w"); + assert_non_null(fp); + + fprintf(fp, "%s", fake_mrmonit_daemon_text); + fclose(fp); + + /* inject the eal init failed */ + int inject_eal_init_failed = 1; + will_return(__wrap_rte_eal_init, inject_eal_init_failed); + + /* should fail, as the eal init failed */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_init_no_service_running(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + unsigned int u32_disable = 0; + marsio_option_set(instance, MARSIO_OPT_EXIT_WHEN_ERR, (void *)&u32_disable, sizeof(u32_disable)); + + /* erase the service daemon monit file */ + remove("/var/run/mrzcpd/mrmonit.daemon"); + + /* should fail, as the service is not running */ + int ret = marsio_init(instance, "test_marsio_init"); + assert_int_equal(ret, -1); + + ret = marsio_destory(instance); + assert_int_equal(ret, 0); +} + +static void testcase_marsio_instance_set_thread_mask_in_cpuset(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + /* should accept */ + cpu_set_t param_cpu_set = {}; + CPU_SET(1, ¶m_cpu_set); + + int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, ¶m_cpu_set, sizeof(param_cpu_set)); + assert_int_equal(ret, 0); + + /* size is not enough, input should be rejected */ + unsigned int cpu_set_small = 0; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, &cpu_set_small, sizeof(cpu_set_small)); + assert_int_equal(ret, -EINVAL); + +#if 0 + cpu_set_t param_cpu_set_get; + marsio_option_get(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, ¶m_cpu_set_get, sizeof(param_cpu_set_get)); + assert_true(CPU_EQUAL(¶m_cpu_set, ¶m_cpu_set_get)); +#endif + + marsio_destory(instance); +} + +static void testcase_marsio_instance_set_thread_num(void ** state) +{ + struct mr_instance * instance = marsio_create(); + assert_non_null(instance); + + /* should accept */ + unsigned int param_thread_num = 4; + int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num, sizeof(param_thread_num)); + assert_int_equal(ret, 0); + + /* size is not enough, input should be rejected */ + uint8_t param_thread_num_u8 = 8; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_u8, sizeof(param_thread_num_u8)); + assert_int_equal(ret, -EINVAL); + + /* size is larger than expected + * FIXME: the input should be rejected */ + uint64_t param_thread_num_u64 = 8; + ret = marsio_option_set(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_u64, sizeof(param_thread_num_u64)); + assert_int_equal(ret, 0); + +#if 0 + unsigned int param_thread_num_get = 0; + marsio_option_get(instance, MARSIO_OPT_THREAD_NUM, ¶m_thread_num_get, sizeof(param_thread_num)); + assert_int_equal(param_thread_num_get, param_thread_num_u64); +#endif + + marsio_destory(instance); +} + +int main(int argc, char * argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "unittest", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = __real_rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + call_real_rte_mp_request_sync = 0; + const struct CMUnitTest testcases_instance[] = { + cmocka_unit_test(testcase_marsio_instance_set_thread_num), + cmocka_unit_test(testcase_marsio_instance_set_thread_mask_in_cpuset), + cmocka_unit_test(testcase_marsio_init_no_service_running), + cmocka_unit_test(testcase_marsio_init_eal_failed), + cmocka_unit_test(testcase_marsio_int_register_failed_by_mp_sync_failed), + cmocka_unit_test(testcase_marsio_init_register_failed_by_errcode), + cmocka_unit_test(testcase_marsio_init_register_succ), + }; + + cmocka_run_group_tests(testcases_instance, NULL, NULL); + rte_eal_cleanup(); +}
\ No newline at end of file diff --git a/app/test/test_marsio_rawio_api.c b/app/test/test_marsio_rawio_api.c new file mode 100644 index 0000000..1bf0ae3 --- /dev/null +++ b/app/test/test_marsio_rawio_api.c @@ -0,0 +1,509 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <string.h> +#include <cmocka.h> +#include <marsio.h> + +#include <rte_mbuf.h> +#include <rte_mempool.h> + +struct rte_mempool * mbuf_pool = NULL; + +int __wrap_vnode_mirror_dequeue_burst(void * cons, unsigned int qid, void * buffs[], unsigned int nr_buffs) +{ + void ** mock_buffs = mock_ptr_type(void **); + unsigned int mock_nr_buffs = mock_type(unsigned int); + unsigned int mock_expect_qid = mock_type(unsigned int); + + if (qid == mock_expect_qid) + { + for (unsigned int i = 0; i < mock_nr_buffs; i++) + { + buffs[i] = mock_buffs[i]; + } + return (int)mock_nr_buffs; + } + else + { + return 0; + } +} + +int __wrap_vnode_mirror_enqueue_bulk(void * prod, unsigned int prodq, struct rte_mbuf * buffs[], + uint32_t hash[], unsigned int nr_buffs) +{ + /* check input parameters */ + check_expected_ptr(buffs); + check_expected(nr_buffs); + + /* fault inject parameter */ + int enq_succ_buff_count = mock_type(int); + assert(nr_buffs >= enq_succ_buff_count); + + /* free the succ enq pkts */ + for (unsigned int i = 0; i < enq_succ_buff_count; i++) + { + rte_pktmbuf_free(buffs[i]); + } + + return 0; +} + +int __wrap_vnode_mirror_rt_object_retrieve(void * prod, unsigned int prodq, struct rte_mbuf * rt_objs[], + unsigned int nr_max_rt_objects) +{ + + void ** mock_buffs = mock_ptr_type(void **); + unsigned int mock_nr_buffs = mock_type(unsigned int); + + for (unsigned int i = 0; i < mock_nr_buffs; i++) + { + rt_objs[i] = mock_buffs[i]; + } + + return (int)mock_nr_buffs; +} + +int __wrap_marsio_buff_free_v2(struct mr_instance * instance, marsio_buff_t * buffs[], unsigned int nr_buffs, + unsigned int flags, unsigned int sid) +{ + for (unsigned int i = 0; i < nr_buffs; i++) + { + rte_pktmbuf_free(buffs[i]); + } + + return 0; +} + +void __wrap_marsio_buff_do_rehash(struct mr_instance * mr_instance, marsio_buff_t * m) +{ + function_called(); +} + +int __wrap_marsio_dp_trace_measurements_can_emit(struct mr_instance * instance, const marsio_buff_t * mbuf, + uint8_t measurement_type) +{ + return 0; +} + +#include <mrapp.h> +struct mr_vdev * __wrap_marsio_open_device(struct mr_instance * instance, const char * devsym, + unsigned int nr_rxstream, + unsigned int nr_txstream) +{ + /* create a fake mr_vdev handle */ + struct mr_vdev * mock_mr_vdev_handle = malloc(sizeof(struct mr_vdev)); + memset(mock_mr_vdev_handle, 0, sizeof(struct mr_vdev)); + + mock_mr_vdev_handle->nr_rxstream = nr_rxstream; + mock_mr_vdev_handle->nr_txstream = nr_txstream; + mock_mr_vdev_handle->instance = instance; + + mock_mr_vdev_handle->vdi = calloc(1, sizeof(struct vdev_instance)); + mock_mr_vdev_handle->tap_representor = NULL; + +#define SZ_VDEV_BUFFER 32 + for (unsigned int i = 0; i < mock_mr_vdev_handle->nr_rxstream; i++) + { + size_t sz_rx_buffer = sizeof(struct mr_vdev_rx_buffer) + sizeof(struct rte_mbuf *) * SZ_VDEV_BUFFER; + mock_mr_vdev_handle->rx_buffer[i] = calloc(1, sz_rx_buffer); + mock_mr_vdev_handle->rx_buffer[i]->size = SZ_VDEV_BUFFER; + } + + for (unsigned int i = 0; i < mock_mr_vdev_handle->nr_txstream; i++) + { + size_t sz_tx_buffer = sizeof(struct mr_vdev_tx_buffer) + sizeof(struct rte_mbuf *) * SZ_VDEV_BUFFER; + mock_mr_vdev_handle->tx_buffer[i] = calloc(1, sz_tx_buffer); + mock_mr_vdev_handle->tx_buffer[i]->size = SZ_VDEV_BUFFER; + } + + assert_non_null(mock_mr_vdev_handle); + return mock_mr_vdev_handle; +} + +void __wrap_marsio_close_device(struct mr_vdev * vdev) +{ + for (unsigned int i = 0; i < vdev->nr_rxstream; i++) + { + free(vdev->rx_buffer[i]); + } + + for (unsigned int i = 0; i < vdev->nr_txstream; i++) + { + free(vdev->tx_buffer[i]); + } + + free(vdev->vdi); + free(vdev); +} + +static void test_recv_burst_api_one_pkt(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL,"mock_mr_vdev", 2, 1); + assert_non_null(mock_mr_vdev); + + struct rte_mbuf * mbufs_to_recv[1]; + mbufs_to_recv[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_recv[0]); + + will_return(__wrap_vnode_mirror_dequeue_burst, mbufs_to_recv); + will_return(__wrap_vnode_mirror_dequeue_burst, 1); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + struct rte_mbuf * mbufs_to_recv_ret[1]; + int ret = marsio_recv_burst(mock_mr_vdev, 0, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 1); + + /* free the mbuf */ + assert_true(mbufs_to_recv_ret[0] == mbufs_to_recv[0]); + rte_pktmbuf_free(mbufs_to_recv[0]); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); + + will_return(__wrap_vnode_mirror_dequeue_burst, NULL); + will_return(__wrap_vnode_mirror_dequeue_burst, 1); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + /* try to recv pkt from another queue */ + ret = marsio_recv_burst(mock_mr_vdev, 1, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 0); + + /* try to recv pkt from out-of-range queue */ + ret = marsio_recv_burst(mock_mr_vdev, 2, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, -EINVAL); +} + +static void test_recv_burst_api_many_pkts(void ** state) +{ + struct rte_mbuf * mbufs_to_recv[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_recv[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_recv[i]); + } + + /* dequeue will get 32 mbufs */ + will_return(__wrap_vnode_mirror_dequeue_burst, mbufs_to_recv); + will_return(__wrap_vnode_mirror_dequeue_burst, 32); + will_return(__wrap_vnode_mirror_dequeue_burst, 0); + + /* call marsio_recv_burst one by one, should get 32 mbufs */ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + for (unsigned int i = 0; i < 32; i++) + { + struct rte_mbuf * mbufs_to_recv_ret[1]; + int ret = marsio_recv_burst(mock_mr_vdev, 0, (marsio_buff_t **)mbufs_to_recv_ret, 1); + assert_int_equal(ret, 1); + + /* free the mbuf */ + assert_true(mbufs_to_recv_ret[0] == mbufs_to_recv[i]); + rte_pktmbuf_free(mbufs_to_recv[i]); + } + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} + +static void test_send_burst_api_one_pkt_succ(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(mock_mr_vdev); + + struct mr_sendpath * mock_sendpath = marsio_sendpath_create_by_vdev(mock_mr_vdev); + assert_non_null(mock_sendpath); + + /* create a mbuf to send */ + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* no packet drop because of backpressure, all the packets should be sent */ + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + will_return(__wrap_vnode_mirror_enqueue_bulk, RTE_DIM(mbufs_to_send)); + + int ret = marsio_send_burst(mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1); + assert_int_equal(ret, 0); + + /* flush */ + struct mr_vdev * vdevs_handles[] = {mock_mr_vdev}; + marsio_poll_wait(mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); + marsio_close_device(mock_mr_vdev); +} + +static void test_send_burst_api_one_pkt_drop_by_backpressure(void ** state) +{ + struct mr_vdev * mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(mock_mr_vdev); + + struct mr_sendpath * mock_sendpath = marsio_sendpath_create_by_vdev(mock_mr_vdev); + assert_non_null(mock_sendpath); + + /* create a mbuf to send */ + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* fault inject, no packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 0); + + /* all packet should be retrieved to simulate the backpressure */ + will_return(__wrap_vnode_mirror_rt_object_retrieve, mbufs_to_send); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 1); + + int ret = marsio_send_burst(mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1); + assert_int_equal(ret, 0); + + /* flush */ + struct mr_vdev * vdevs_handles[] = {mock_mr_vdev}; + marsio_poll_wait(mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); + marsio_close_device(mock_mr_vdev); +} + +struct send_with_options_test_state +{ + struct mr_vdev * mock_mr_vdev; + struct mr_sendpath * mock_sendpath; +}; + +/* test group 2: send with options */ +static int testcase_group_SEND_WITH_OPTIONS_setup(void ** state) +{ + struct send_with_options_test_state * test_state = malloc(sizeof(struct send_with_options_test_state)); + memset(test_state, 0, sizeof(struct send_with_options_test_state)); + + test_state->mock_mr_vdev = marsio_open_device(NULL, "mock_mr_vdev", 1, 1); + assert_non_null(test_state->mock_mr_vdev); + + test_state->mock_sendpath = marsio_sendpath_create_by_vdev(test_state->mock_mr_vdev); + assert_non_null(test_state->mock_sendpath); + + *state = test_state; + return 0; +} + +static int testcase_group_SEND_WITH_OPTIONS_teardown(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + if (test_state != NULL) + { + marsio_close_device(test_state->mock_mr_vdev); + marsio_sendpath_destory(test_state->mock_sendpath); + free(test_state); + } + + return 0; +} + +static void test_send_with_options_do_not_free(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[0]); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* packet should be sent successfully, no packet drop */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 1); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, do not free the packet */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1, + MARSIO_SEND_OPT_NO_FREE); + + /* always success */ + assert_int_equal(ret, 0); + + /* since the pkt has been set to no free */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 1); + + /* free the mbuf */ + rte_pktmbuf_free(mbufs_to_send[0]); + assert_true(rte_mempool_full(mbuf_pool)); +} + +static void test_send_with_options_rehash(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[1]; + mbufs_to_send[0] = rte_pktmbuf_alloc(mbuf_pool); + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 1); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 1); + + /* packet should be sent successfully, no packet drop */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 1); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* marsio_do_rehash should be called */ + expect_function_call(__wrap_marsio_buff_do_rehash); + + /* call send with option, do rehash */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 1, + MARSIO_SEND_OPT_REHASH); + + /* always success */ + assert_int_equal(ret, 0); + + /* check the mbuf leak */ + assert_true(rte_mempool_full(mbuf_pool)); +} + +static void test_send_with_options_many_pkts(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, no options */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 32, 0); + assert_int_equal(ret, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} + +#if 0 +static void test_mix_send_with_option_and_send_burst(void ** state) +{ + struct send_with_options_test_state * test_state = *state; + assert_non_null(test_state); + + struct rte_mbuf * mbufs_to_send[32] = {}; + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* call send with option, no options */ + int ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 32, 0); + assert_int_equal(ret, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); + + /* free the mbuf */ + for (unsigned int i = 0; i < 32; i++) + { + mbufs_to_send[i] = rte_pktmbuf_alloc(mbuf_pool); + assert_non_null(mbufs_to_send[i]); + } + + /* mbufs_to_send should be call as parameter for vnode_mirror_enqueue_bulk */ + expect_memory(__wrap_vnode_mirror_enqueue_bulk, buffs, mbufs_to_send, 32); + expect_value(__wrap_vnode_mirror_enqueue_bulk, nr_buffs, 32); + + /* fault inject, all packet send successfully */ + will_return(__wrap_vnode_mirror_enqueue_bulk, 32); + will_return(__wrap_vnode_mirror_rt_object_retrieve, NULL); + will_return(__wrap_vnode_mirror_rt_object_retrieve, 0); + + /* first 16 mbufs, send by send burst */ + ret = marsio_send_burst(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send, 16); + assert_int_equal(ret, 0); + + /* second 16 mbufs, send by send burst with options */ + ret = marsio_send_burst_with_options(test_state->mock_sendpath, 0, (marsio_buff_t **)mbufs_to_send + 16, 16, 0); + assert_int_equal(ret, 0); + + /* poll and wait */ + struct mr_vdev * vdevs_handles[] = {test_state->mock_mr_vdev}; + marsio_poll_wait(test_state->mock_mr_vdev->instance, vdevs_handles, RTE_DIM(vdevs_handles), 0, 0); + + /* make sure no mbuf leak */ + assert_int_equal(rte_mempool_in_use_count(mbuf_pool), 0); +} +#endif + +int main(int argc, char * argv[]) +{ + /* generate the eal args */ + static char * eal_args[] = { + "test_marsio_rawio_api", + "-c 0x1", + "--no-huge", + "--no-pci", + }; + + /* run the eal with no huge pages */ + int ret = rte_eal_init(RTE_DIM(eal_args), eal_args); + if (ret < 0) + { + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + } + + /* init the mbuf pool */ + mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 8192, 32, 0, RTE_MBUF_DEFAULT_BUF_SIZE, SOCKET_ID_ANY); + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_recv_burst_api_one_pkt), + cmocka_unit_test(test_recv_burst_api_many_pkts), + cmocka_unit_test(test_send_burst_api_one_pkt_succ), + cmocka_unit_test(test_send_burst_api_one_pkt_drop_by_backpressure), + }; + + const struct CMUnitTest testcase_send_with_options[] = { + cmocka_unit_test_setup_teardown(test_send_with_options_do_not_free, NULL, NULL), + cmocka_unit_test_setup_teardown(test_send_with_options_rehash, NULL, NULL), + cmocka_unit_test_setup_teardown(test_send_with_options_many_pkts, NULL, NULL), +#if 0 + cmocka_unit_test_setup_teardown(test_mix_send_with_option_and_send_burst, NULL, NULL), +#endif + }; + + cmocka_run_group_tests(tests, NULL, NULL); + cmocka_run_group_tests(testcase_send_with_options, testcase_group_SEND_WITH_OPTIONS_setup, + testcase_group_SEND_WITH_OPTIONS_teardown); +}
\ No newline at end of file |
