summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
author陆秋文 <[email protected]>2024-07-15 09:48:50 +0000
committer陆秋文 <[email protected]>2024-07-15 09:48:50 +0000
commitf0e50964001c56042150c9c49284bf0aaa531a7c (patch)
treedd15b7248485ecade179524a7670630f21be68ff /app
parent24f4ab0940ef3652908b3a5968527951c53f66b8 (diff)
Feature mock api by cmocka
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt47
-rw-r--r--app/include/mrapp.h3
-rw-r--r--app/src/dp_trace.c9
-rw-r--r--app/src/marsio.c82
-rw-r--r--app/src/mrb.c1
-rw-r--r--app/src/rawio.c4
-rw-r--r--app/test/test_marsio_instance_api.c356
-rw-r--r--app/test/test_marsio_rawio_api.c509
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(&reg_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, &param_cpu_set);
+
+ int ret = marsio_option_set(instance, MARSIO_OPT_THREAD_MASK_IN_CPUSET, &param_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, &param_cpu_set_get, sizeof(param_cpu_set_get));
+ assert_true(CPU_EQUAL(&param_cpu_set, &param_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, &param_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, &param_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, &param_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, &param_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