libmemif: added tests

This patch provides unit tests for libmemif written in Unity

Type: test

Signed-off-by: Daniel Béreš <dberes@cisco.com>
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Change-Id: I19116def6e6d28efd5f460c93911245474a11321
diff --git a/extras/libmemif/CMakeLists.txt b/extras/libmemif/CMakeLists.txt
index b6b658c..8f057e9 100644
--- a/extras/libmemif/CMakeLists.txt
+++ b/extras/libmemif/CMakeLists.txt
@@ -18,6 +18,35 @@
 
 include(CheckCCompilerFlag)
 include(CheckFunctionExists)
+find_package(Git REQUIRED)
+
+include(ExternalProject)
+set(UNITY unity_project)
+
+ExternalProject_Add(
+    unity_project
+    GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity.git
+    GIT_TAG cf949f45ca6d172a177b00da21310607b97bc7a7
+    PREFIX ${PROJECT_BINARY_DIR}/external/${UNITY}
+    INSTALL_COMMAND cmake --install . --prefix ${PROJECT_BINARY_DIR}
+
+)
+set_source_files_properties(
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/src/unity.c
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/fixture/src/unity_fixture.c
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/memory/src/unity_memory.c
+  PROPERTIES GENERATED TRUE)
+add_library(unity STATIC
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/src/unity.c
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/fixture/src/unity_fixture.c
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/memory/src/unity_memory.c
+)
+target_include_directories(unity PUBLIC
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/src/
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/fixture/src/
+  ${PROJECT_BINARY_DIR}/external/${UNITY}/src/${UNITY}/extras/memory/src/
+)
+add_dependencies(unity unity_project)
 
 if (NOT CMAKE_BUILD_TYPE)
   message(STATUS "No build type selected, default to Release")
@@ -42,6 +71,9 @@
 add_subdirectory(src)
 add_subdirectory(examples)
 
+enable_testing()
+include(CTest)
+add_subdirectory(test)
 ##############################################################################
 # Packaging
 ##############################################################################
diff --git a/extras/libmemif/docs/buildinstructions_doc.rst b/extras/libmemif/docs/buildinstructions_doc.rst
index f7770fc..6609f7a 100644
--- a/extras/libmemif/docs/buildinstructions_doc.rst
+++ b/extras/libmemif/docs/buildinstructions_doc.rst
@@ -49,6 +49,26 @@
             -?      Show help and exit.
             -v      Show libmemif and memif version information and exit.
 
+Running tests:
+--------------
+
+Tests needs to their proper functioning Unity framework which is depended externally and cloned from official git repository::
+
+    mkdir -p extras/libmemif/build
+    cd extras/libmemif/build
+    cmake ..
+    make
+    ctest
+
+``ctest`` will execute the tests and print out brief information about test suites with their statuses.
+
+In case we want verbose: ::
+
+     ctest --verbose
+     ctest --extra-verbose
+
+If there are any needs to debug tests, just add to cmake command ``-DCMAKE_BUILD_TYPE=Debug`` flag.
+
 Use Cases
 ---------
 
diff --git a/extras/libmemif/src/main.c b/extras/libmemif/src/main.c
index e735ee3..e87d4c5 100644
--- a/extras/libmemif/src/main.c
+++ b/extras/libmemif/src/main.c
@@ -412,11 +412,12 @@
   if (ms->timer_fd >= 0)
     {
       uint64_t u64;
+      ssize_t __attribute__ ((unused)) r;
       /*
 	Have to read the timer fd else it stays read-ready
 	and makes epoll_pwait() return without sleeping
       */
-      read (ms->timer_fd, &u64, sizeof (u64));
+      r = read (ms->timer_fd, &u64, sizeof (u64));
     }
 
   /* loop ms->slave_interfaces and request connection for disconnected ones */
diff --git a/extras/libmemif/test/CMakeLists.txt b/extras/libmemif/test/CMakeLists.txt
new file mode 100644
index 0000000..cdb0b87
--- /dev/null
+++ b/extras/libmemif/test/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(suite_socket)
+add_subdirectory(suite_main)
diff --git a/extras/libmemif/test/suite_main/CMakeLists.txt b/extras/libmemif/test/suite_main/CMakeLists.txt
new file mode 100644
index 0000000..7a29400
--- /dev/null
+++ b/extras/libmemif/test/suite_main/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.0)
+
+set (This MemifMainTest)
+
+set (Sources
+    memif_main_test.c)
+
+add_executable(${This} ${Sources})
+
+target_link_libraries(${This} PUBLIC
+    unity
+    memif
+)
+
+add_test(
+    NAME ${This}
+    COMMAND ${This}
+)
diff --git a/extras/libmemif/test/suite_main/memif_main_test.c b/extras/libmemif/test/suite_main/memif_main_test.c
new file mode 100644
index 0000000..d6b2e79
--- /dev/null
+++ b/extras/libmemif/test/suite_main/memif_main_test.c
@@ -0,0 +1,388 @@
+#include <main.c>
+#include <unity_fixture.h>
+#include <memif_private.h>
+#include <stdlib.h>
+
+#define MEMIF_VERSION_STR    "2.0"
+#define MEMIF_BUFFER_SIZE    2048
+#define MEMIF_INTERFACE_NAME "memif0/0"
+#define MEMIF_LOG_RING_SIZE  10
+#define MEMIF_SECRET	     "psst"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+static memif_socket_handle_t socket_handler;
+static memif_conn_handle_t conn;
+
+static memif_socket_args_t memif_socket_args;
+static memif_conn_args_t memif_conn_args;
+
+static int dummy_on_connect (void *, void *);
+static int dummy_on_disconnect (void *, void *);
+static int dummy_on_interrupt (void *, void *, uint16_t);
+
+static int
+dummy_on_connect (void *a, void *b)
+{
+}
+static int
+dummy_on_disconnect (void *a, void *b)
+{
+}
+static int
+dummy_on_interrupt (void *a, void *b, uint16_t c)
+{
+}
+
+static void
+init_conn_args ()
+{
+  memif_connection_t *c = (memif_connection_t *) conn;
+  memset (c, 0, sizeof (memif_connection_t));
+  c->args = (memif_conn_args_t){ .buffer_size = MEMIF_BUFFER_SIZE,
+				 .interface_id = 0,
+				 .interface_name = MEMIF_INTERFACE_NAME,
+				 .is_master = 0,
+				 .log2_ring_size = MEMIF_LOG_RING_SIZE,
+				 .mode = 0,
+				 .num_m2s_rings = 1,
+				 .num_s2m_rings = 1,
+				 .secret = MEMIF_SECRET,
+				 .socket = &socket_handler };
+}
+
+static void
+init_connection ()
+{
+  conn = malloc (sizeof (memif_connection_t));
+  memif_connection_t *c = (memif_connection_t *) conn;
+  init_conn_args ();
+}
+
+static void
+init_socket ()
+{
+  memif_socket_t *ms = malloc (sizeof (memif_socket_t));
+  socket_handler = ms;
+  /* default values */
+  memset (ms, 0, sizeof (memif_socket_t));
+  ms->epfd = 3;
+  ms->listener_fd = 4;
+  ms->poll_cancel_fd = 5;
+  ms->timer_fd = -1;
+
+  TAILQ_INIT (&ms->master_interfaces);
+  TAILQ_INIT (&ms->slave_interfaces);
+}
+
+static void
+init_socket_args ()
+{
+  strncpy (memif_socket_args.app_name, MEMIF_DEFAULT_APP_NAME,
+	   strlen (MEMIF_DEFAULT_APP_NAME));
+  strncpy (memif_socket_args.path, MEMIF_DEFAULT_SOCKET_PATH,
+	   strlen (MEMIF_DEFAULT_SOCKET_PATH));
+}
+
+static void
+delete_connection ()
+{
+  free (conn);
+}
+
+TEST_GROUP (MemifMain);
+
+TEST_SETUP (MemifMain) {}
+
+TEST_TEAR_DOWN (MemifMain) {}
+
+TEST (MemifMain, MemifGetVersion)
+{
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_VERSION, memif_get_version ());
+}
+
+TEST (MemifMain, MemifGetVersionStr)
+{
+  TEST_ASSERT_EQUAL_STRING (MEMIF_VERSION_STR, memif_get_version_str ());
+}
+
+TEST (MemifMain, MemifStrError)
+{
+  for (size_t i = 0; i < ERRLIST_LEN; i++)
+    {
+      TEST_ASSERT_EQUAL_STRING (memif_strerror (i), memif_errlist[i]);
+    }
+  TEST_ASSERT_EQUAL_STRING (memif_strerror (ERRLIST_LEN + 1),
+			    MEMIF_ERR_UNDEFINED);
+}
+
+TEST (MemifMain, MemifGetDetails)
+{
+  init_socket ();
+  init_connection ();
+  memif_details_t md;
+  ssize_t buflen = 2048;
+  char buf[buflen];
+  memif_get_details (conn, &md, buf, buflen);
+
+  TEST_ASSERT_EQUAL_STRING (MEMIF_INTERFACE_NAME, md.if_name);
+  TEST_ASSERT_EQUAL_UINT32 (0, md.id);
+  TEST_ASSERT_EQUAL_STRING (MEMIF_SECRET, md.secret);
+  TEST_ASSERT_EQUAL_UINT8 (1, md.role);
+  TEST_ASSERT_EQUAL_UINT8 (0, md.mode);
+  TEST_ASSERT_EQUAL_UINT8 (0, md.link_up_down);
+}
+
+TEST (MemifMain, MemifControl_fd_update_add_del_epoll_fd)
+{
+  init_socket_args ();
+  memif_create_socket (&socket_handler, &memif_socket_args, NULL);
+  memif_fd_event_t fde;
+  memif_fd_event_data_t *fdata;
+  void *ctx;
+  memif_socket_t *ms = (memif_socket_t *) socket_handler;
+
+  fdata = ms->args.alloc (sizeof (*fdata));
+  fdata->event_handler = memif_poll_cancel_handler;
+  fdata->private_ctx = ms;
+
+  fde.fd = eventfd (0, EFD_NONBLOCK);
+  fde.private_ctx = fdata;
+  fde.type = MEMIF_FD_EVENT_READ;
+  ctx = ms->epfd != -1 ? ms : ms->private_ctx;
+  TEST_ASSERT_EQUAL_INT (0, memif_control_fd_update (fde, ctx));
+  fde.type = MEMIF_FD_EVENT_DEL;
+  TEST_ASSERT_EQUAL_INT (0, memif_control_fd_update (fde, ctx));
+}
+
+TEST (MemifMain, MemifSetConnectionRequestTimer)
+{
+  memif_socket_handle_t msh =
+    (memif_socket_handle_t) malloc (sizeof (memif_socket_t));
+  memif_socket_t *ms = (memif_socket_t *) msh;
+  struct itimerspec timer;
+  memif_fd_event_t fde;
+  memif_fd_event_data_t *fdata;
+  int i, err = MEMIF_ERR_SUCCESS;
+  void *ctx;
+  memset (ms, 0, sizeof (memif_socket_t));
+  ms->epfd = -1;
+  ms->listener_fd = -1;
+  ms->poll_cancel_fd = -1;
+
+  TAILQ_INIT (&ms->master_interfaces);
+  TAILQ_INIT (&ms->slave_interfaces);
+  ms->timer_fd = -1;
+  ms->args.alloc = malloc;
+  ms->args.free = free;
+  ms->args.realloc = realloc;
+
+  if (ms->args.on_control_fd_update == NULL)
+    {
+      ms->epfd = epoll_create (1);
+      memif_control_fd_update_register (ms, memif_control_fd_update);
+      ms->poll_cancel_fd = eventfd (0, EFD_NONBLOCK);
+
+      fdata = ms->args.alloc (sizeof (*fdata));
+      fdata->event_handler = memif_poll_cancel_handler;
+      fdata->private_ctx = ms;
+
+      fde.fd = ms->poll_cancel_fd;
+      fde.type = MEMIF_FD_EVENT_READ;
+      fde.private_ctx = fdata;
+      ctx = ms->epfd != -1 ? ms : ms->private_ctx;
+      ms->args.on_control_fd_update (fde, ctx);
+    }
+
+  timer.it_value.tv_sec = 2;
+  timer.it_value.tv_nsec = 0;
+  timer.it_interval.tv_sec = 2;
+  timer.it_value.tv_nsec = 0;
+  memif_set_connection_request_timer (msh, timer);
+
+  TEST_ASSERT_NOT_EQUAL_INT (-1, ms->timer_fd);
+  memif_delete_socket (&msh);
+}
+
+TEST (MemifMain, MemifSetConnectionRequestTimerNoTimer)
+{
+  memif_socket_handle_t msh =
+    (memif_socket_handle_t) malloc (sizeof (memif_socket_t));
+  memif_socket_t *ms = (memif_socket_t *) msh;
+  struct itimerspec timer;
+  memif_fd_event_t fde;
+  memif_fd_event_data_t *fdata;
+  int i, err = MEMIF_ERR_SUCCESS;
+  void *ctx;
+  memset (ms, 0, sizeof (memif_socket_t));
+  ms->epfd = -1;
+  ms->listener_fd = -1;
+  ms->poll_cancel_fd = -1;
+
+  TAILQ_INIT (&ms->master_interfaces);
+  TAILQ_INIT (&ms->slave_interfaces);
+  ms->timer_fd = -1;
+  ms->args.alloc = malloc;
+  ms->args.free = free;
+  ms->args.realloc = realloc;
+
+  if (ms->args.on_control_fd_update == NULL)
+    {
+      ms->epfd = epoll_create (1);
+      /* register default fd update callback */
+      memif_control_fd_update_register (ms, memif_control_fd_update);
+      ms->poll_cancel_fd = eventfd (0, EFD_NONBLOCK);
+      if (ms->poll_cancel_fd < 0)
+	{
+	  err = errno;
+	  DBG ("eventfd: %s", strerror (err));
+	  // return memif_syscall_error_handler (err);
+	}
+      /* add interrupt fd to epfd */
+      fdata = ms->args.alloc (sizeof (*fdata));
+      fdata->event_handler = memif_poll_cancel_handler;
+      fdata->private_ctx = ms;
+
+      fde.fd = ms->poll_cancel_fd;
+      fde.type = MEMIF_FD_EVENT_READ;
+      fde.private_ctx = fdata;
+      ctx = ms->epfd != -1 ? ms : ms->private_ctx;
+      ms->args.on_control_fd_update (fde, ctx);
+    }
+  memset (&timer, 0, sizeof (struct itimerspec));
+  memif_set_connection_request_timer (msh, timer);
+
+  TEST_ASSERT_EQUAL_INT (-1, ms->timer_fd);
+  memif_delete_socket (msh);
+  memif_delete_socket (&msh);
+}
+
+TEST_GROUP (MemifInterface);
+
+TEST_SETUP (MemifInterface)
+{
+  socket_handler = NULL;
+  conn = NULL;
+  memset (&memif_socket_args, 0, sizeof (memif_socket_args_t));
+  memset (&memif_conn_args, 0, sizeof (memif_conn_args_t));
+
+  memif_socket_args = (memif_socket_args_t){
+    .app_name = "TEST",
+    .path = "@memif.sock",
+  };
+  int err = memif_create_socket (&socket_handler, &memif_socket_args, NULL);
+  if (err)
+    exit (EXIT_FAILURE);
+  memif_conn_args.socket = socket_handler;
+  memif_conn_args.interface_id = 0;
+  strncpy (memif_conn_args.interface_name, MEMIF_INTERFACE_NAME,
+	   sizeof (memif_conn_args.interface_name));
+}
+
+TEST_TEAR_DOWN (MemifInterface)
+{
+  memif_delete (&conn);
+  memif_delete_socket (&socket_handler);
+  memset (&memif_socket_args, 0, sizeof (memif_socket_args_t));
+  memset (&memif_conn_args, 0, sizeof (memif_conn_args_t));
+  memif_delete (&conn);
+}
+
+TEST (MemifInterface, MemifCreateMaster)
+{
+  memif_conn_args.is_master = 1;
+  int err = memif_create (&conn, &memif_conn_args, dummy_on_connect,
+			  dummy_on_disconnect, dummy_on_interrupt, NULL);
+
+  TEST_ASSERT_EQUAL_INT (MEMIF_ERR_SUCCESS, err);
+
+  memif_socket_t *ms = (memif_socket_t *) socket_handler;
+  memif_connection_t *mc = conn;
+
+  TEST_ASSERT_NULL (ms->slave_interfaces.tqh_first);
+  TEST_ASSERT_NOT_NULL (ms->master_interfaces.tqh_first);
+  TEST_ASSERT_NOT_NULL (mc->args.socket);
+  TEST_ASSERT_EQUAL_INT (mc->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.log2_ring_size,
+			   MEMIF_DEFAULT_LOG2_RING_SIZE);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.num_m2s_rings, 1);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.num_s2m_rings, 1);
+}
+TEST (MemifInterface, MemifCreateSlave)
+{
+  memif_conn_args.is_master = 0;
+
+  int err = memif_create (&conn, &memif_conn_args, dummy_on_connect,
+			  dummy_on_disconnect, dummy_on_interrupt, NULL);
+
+  memif_socket_t *ms = (memif_socket_t *) socket_handler;
+  memif_connection_t *mc = conn;
+
+  TEST_ASSERT_EQUAL_INT (MEMIF_ERR_SUCCESS, err);
+  TEST_ASSERT_NULL (ms->master_interfaces.tqh_first);
+  TEST_ASSERT_NOT_NULL (ms->slave_interfaces.tqh_first);
+  TEST_ASSERT_NOT_NULL (mc->args.socket);
+  TEST_ASSERT_EQUAL_INT (mc->args.buffer_size, MEMIF_DEFAULT_BUFFER_SIZE);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.log2_ring_size,
+			   MEMIF_DEFAULT_LOG2_RING_SIZE);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.num_m2s_rings, 1);
+  TEST_ASSERT_EQUAL_UINT8 (mc->args.num_s2m_rings, 1);
+}
+
+TEST (MemifInterface, MemifDelete)
+{
+  memif_conn_args.is_master = 0;
+
+  memif_create (&conn, &memif_conn_args, dummy_on_connect, dummy_on_disconnect,
+		dummy_on_interrupt, NULL);
+
+  int err = memif_delete (&conn);
+
+  TEST_ASSERT_EQUAL_INT (MEMIF_ERR_SUCCESS, err);
+  TEST_ASSERT_NULL (conn);
+}
+
+TEST (MemifMain, MemifPollEvent)
+{
+  init_socket_args ();
+  memif_create_socket (&socket_handler, &memif_socket_args, NULL);
+  memif_socket_t *ms = (memif_socket_t *) socket_handler;
+  uint64_t buf = 1;
+  int ret = write (ms->poll_cancel_fd, &buf, sizeof (buf));
+  TEST_ASSERT_EQUAL (8, ret);
+  TEST_ASSERT_EQUAL (MEMIF_ERR_POLL_CANCEL,
+		     memif_poll_event (socket_handler, -1));
+}
+
+TEST_GROUP_RUNNER (MemifMain){
+  RUN_TEST_CASE (MemifMain, MemifGetVersion)
+    RUN_TEST_CASE (MemifMain, MemifGetVersionStr)
+      RUN_TEST_CASE (MemifMain, MemifStrError)
+	RUN_TEST_CASE (MemifMain, MemifGetDetails)
+	  RUN_TEST_CASE (MemifMain, MemifControl_fd_update_add_del_epoll_fd)
+	    RUN_TEST_CASE (MemifMain, MemifSetConnectionRequestTimer)
+	      RUN_TEST_CASE (MemifMain, MemifSetConnectionRequestTimerNoTimer)
+		RUN_TEST_CASE (MemifMain, MemifPollEvent)
+}
+
+TEST_GROUP_RUNNER (MemifInterface)
+{
+  RUN_TEST_CASE (MemifInterface, MemifCreateMaster);
+  RUN_TEST_CASE (MemifInterface, MemifCreateSlave);
+  RUN_TEST_CASE (MemifInterface, MemifDelete);
+}
+static void
+RunAllTests (void)
+{
+  RUN_TEST_GROUP (MemifMain);
+  RUN_TEST_GROUP (MemifInterface);
+}
+
+int
+main (int argc, const char *argv[])
+{
+  return UnityMain (argc, argv, RunAllTests);
+}
diff --git a/extras/libmemif/test/suite_socket/CMakeLists.txt b/extras/libmemif/test/suite_socket/CMakeLists.txt
new file mode 100644
index 0000000..5ac66a0
--- /dev/null
+++ b/extras/libmemif/test/suite_socket/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.0)
+
+set (This MemifSocketTest)
+
+set (Sources
+    memif_socket_test.c)
+
+add_executable(${This} ${Sources})
+
+target_link_libraries(${This} PUBLIC
+    unity
+    memif
+)
+
+add_test(
+    NAME ${This}
+    COMMAND ${This}
+)
diff --git a/extras/libmemif/test/suite_socket/memif_socket_test.c b/extras/libmemif/test/suite_socket/memif_socket_test.c
new file mode 100644
index 0000000..4e12314
--- /dev/null
+++ b/extras/libmemif/test/suite_socket/memif_socket_test.c
@@ -0,0 +1,401 @@
+#include <main.c>
+#include <socket.c>
+
+#include <unity_fixture.h>
+#include <libmemif.h>
+#include <memif_private.h>
+#include <stdlib.h>
+
+#define TEST_APP_NAME	   "unit_test_app"
+#define MEMIF_TEST_IF_NAME "unit_test_if"
+#define MEMIF_TEST_SECRET  "psst"
+#define TEST_IF_ID	   0
+#define TEST_SOCKET_PATH   "@memif.sock"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+static int err;
+static memif_socket_handle_t memif_socket;
+static memif_socket_args_t memif_socket_args;
+static memif_control_channel_t *cc;
+
+static void
+init_socket_args ()
+{
+  strncpy (memif_socket_args.app_name, MEMIF_DEFAULT_APP_NAME,
+	   strlen (MEMIF_DEFAULT_APP_NAME));
+  sprintf (memif_socket_args.path, "%s", MEMIF_DEFAULT_SOCKET_PATH);
+}
+
+TEST_GROUP (MemifSocket);
+
+TEST_SETUP (MemifSocket)
+{
+  memif_socket = NULL;
+  static int err = 0;
+}
+
+TEST_TEAR_DOWN (MemifSocket) {}
+
+TEST (MemifSocket, CreateSocket)
+{
+
+  memif_socket_args_t memif_socket_args = {
+    .app_name = TEST_APP_NAME,
+    .path = TEST_SOCKET_PATH,
+  };
+  err = memif_create_socket (&memif_socket, &memif_socket_args, NULL);
+
+  TEST_ASSERT_EQUAL_INT (0, err);
+  TEST_ASSERT_NOT_NULL (memif_socket);
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  TEST_ASSERT_EQUAL_STRING (ms->args.app_name, TEST_APP_NAME);
+  TEST_ASSERT_EQUAL_STRING (ms->args.path, TEST_SOCKET_PATH);
+  TEST_ASSERT_EQUAL_PTR (ms->args.on_control_fd_update,
+			 memif_control_fd_update);
+  TEST_ASSERT_EQUAL_PTR (ms->args.alloc, malloc);
+  TEST_ASSERT_EQUAL_PTR (ms->args.realloc, realloc);
+  TEST_ASSERT_EQUAL_PTR (ms->args.free, free);
+
+  TEST_ASSERT_NOT_EQUAL_INT (ms->epfd, -1);
+  TEST_ASSERT_NOT_EQUAL_INT (ms->poll_cancel_fd, -1);
+
+  memif_delete_socket (&memif_socket);
+}
+
+TEST (MemifSocket, DeleteSocket)
+{
+
+  memif_socket_args_t memif_socket_args = {
+    .app_name = TEST_APP_NAME,
+    .path = TEST_SOCKET_PATH,
+  };
+  memif_create_socket (&memif_socket, &memif_socket_args, NULL);
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+  err = memif_delete_socket (&memif_socket);
+  TEST_ASSERT_EQUAL_INT (MEMIF_ERR_SUCCESS, err);
+  TEST_ASSERT_NULL (memif_socket);
+}
+
+TEST_GROUP (MemifControlChannel);
+
+TEST_SETUP (MemifControlChannel)
+{
+  memif_socket = NULL;
+  static int err = 0;
+  init_socket_args ();
+  memif_create_socket (&memif_socket, &memif_socket_args, NULL);
+  cc = (memif_control_channel_t *) malloc (sizeof (memif_control_channel_t));
+}
+
+TEST_TEAR_DOWN (MemifControlChannel) { free (cc); }
+
+TEST (MemifControlChannel, EnqAck)
+{
+  memif_connection_t conn;
+  memif_msg_queue_elt_t *e;
+  cc->fd = 5;
+  cc->conn = NULL;
+  cc->sock = memif_socket;
+
+  TAILQ_INIT (&cc->msg_queue);
+  memif_msg_enq_ack (cc);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_ACK, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+}
+
+TEST (MemifControlChannel, EnqHello)
+{
+  memif_connection_t conn;
+  memif_msg_queue_elt_t *e;
+  cc->fd = 5;
+  cc->conn = NULL;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  memif_msg_enq_hello (cc);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_HELLO, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+  memif_msg_hello_t h = e->msg.hello;
+  TEST_ASSERT_EQUAL_INT (MEMIF_MAX_LOG2_RING_SIZE, h.max_log2_ring_size);
+  TEST_ASSERT_EQUAL_INT (MEMIF_VERSION, h.min_version);
+  TEST_ASSERT_EQUAL_INT (MEMIF_VERSION, h.max_version);
+  TEST_ASSERT_EQUAL_INT (MEMIF_MAX_S2M_RING, h.max_s2m_ring);
+  TEST_ASSERT_EQUAL_INT (MEMIF_MAX_M2S_RING, h.max_m2s_ring);
+  TEST_ASSERT_EQUAL_INT (MEMIF_MAX_REGION, h.max_region);
+}
+
+TEST (MemifControlChannel, EnqInit)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  memif_msg_enq_init (cc);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_INIT, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+  memif_msg_init_t h = e->msg.init;
+
+  TEST_ASSERT_EQUAL_INT (11, h.id);
+  TEST_ASSERT_EQUAL_INT (1, h.mode);
+  TEST_ASSERT_EQUAL_STRING (MEMIF_DEFAULT_APP_NAME, h.name);
+  TEST_ASSERT_EQUAL_STRING (MEMIF_TEST_SECRET, h.secret);
+  TEST_ASSERT_EQUAL_INT (MEMIF_VERSION, h.version);
+}
+
+TEST (MemifControlChannel, EnqAddRegion)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  memset (cc, 0, sizeof (memif_msg_queue_elt_t));
+  memset (&conn, 0, sizeof (memif_connection_t));
+
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  conn.args.socket = memif_socket;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  conn.run_args.num_s2m_rings = 1;
+  conn.run_args.num_m2s_rings = 1;
+  conn.run_args.log2_ring_size = MEMIF_DEFAULT_LOG2_RING_SIZE;
+  conn.run_args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+  memif_add_region (&conn, 1);
+
+  memif_msg_enq_add_region (cc, 0);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+  memif_msg_add_region_t h = e->msg.add_region;
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_ADD_REGION, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (conn.regions[0].fd, e->fd);
+
+  TEST_ASSERT_EQUAL_INT (0, h.index);
+  TEST_ASSERT_EQUAL_INT (conn.regions[0].region_size, h.size);
+
+  close (conn.regions[0].fd);
+}
+
+TEST (MemifControlChannel, EnqAddRing)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  memset (cc, 0, sizeof (memif_msg_queue_elt_t));
+  memset (&conn, 0, sizeof (memif_connection_t));
+
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  conn.args.socket = memif_socket;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  conn.run_args.num_s2m_rings = 1;
+  conn.run_args.num_m2s_rings = 1;
+  conn.run_args.log2_ring_size = MEMIF_DEFAULT_LOG2_RING_SIZE;
+  conn.run_args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+  memif_add_region (&conn, 1);
+  memif_init_queues (&conn);
+  memif_msg_enq_add_ring (cc, 0, MEMIF_RING_M2S);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+  memif_msg_add_ring_t h = e->msg.add_ring;
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_ADD_RING, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (conn.rx_queues[0].int_fd, e->fd);
+
+  TEST_ASSERT_EQUAL_INT (0, h.flags);
+  TEST_ASSERT_EQUAL_INT (0, h.index);
+  TEST_ASSERT_EQUAL_INT (conn.rx_queues[0].region, h.region);
+  TEST_ASSERT_EQUAL_INT (conn.rx_queues[0].offset, h.offset);
+  TEST_ASSERT_EQUAL_INT (conn.rx_queues[0].log2_ring_size, h.log2_ring_size);
+  TEST_ASSERT_EQUAL_INT (0, h.private_hdr_size);
+
+  close (conn.regions[0].fd);
+}
+TEST (MemifControlChannel, EnqConnect)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  memset (cc, 0, sizeof (memif_msg_queue_elt_t));
+  memset (&conn, 0, sizeof (memif_connection_t));
+
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  conn.args.socket = memif_socket;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+  strlcpy ((char *) conn.args.interface_name, MEMIF_TEST_IF_NAME,
+	   sizeof (MEMIF_TEST_IF_NAME));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  conn.run_args.num_s2m_rings = 1;
+  conn.run_args.num_m2s_rings = 1;
+  conn.run_args.log2_ring_size = MEMIF_DEFAULT_LOG2_RING_SIZE;
+  conn.run_args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+  memif_add_region (&conn, 1);
+  memif_init_queues (&conn);
+  memif_msg_enq_connect (cc);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+  memif_msg_connect_t h = e->msg.connect;
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_CONNECT, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+
+  TEST_ASSERT_EQUAL_STRING (MEMIF_TEST_IF_NAME, h.if_name);
+
+  close (conn.regions[0].fd);
+}
+
+TEST (MemifControlChannel, EnqConnected)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  memset (cc, 0, sizeof (memif_msg_queue_elt_t));
+  memset (&conn, 0, sizeof (memif_connection_t));
+
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  conn.args.socket = memif_socket;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+  strlcpy ((char *) conn.args.interface_name, MEMIF_TEST_IF_NAME,
+	   sizeof (MEMIF_TEST_IF_NAME));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+
+  conn.run_args.num_s2m_rings = 1;
+  conn.run_args.num_m2s_rings = 1;
+  conn.run_args.log2_ring_size = MEMIF_DEFAULT_LOG2_RING_SIZE;
+  conn.run_args.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+  memif_add_region (&conn, 1);
+  memif_init_queues (&conn);
+  memif_msg_enq_connect (cc);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+  memif_msg_connected_t h = e->msg.connected;
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_CONNECT, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+
+  TEST_ASSERT_EQUAL_STRING (MEMIF_TEST_IF_NAME, h.if_name);
+
+  close (conn.regions[0].fd);
+}
+
+TEST (MemifControlChannel, EnqDisconnect)
+{
+  memif_msg_queue_elt_t *e;
+  memif_connection_t conn;
+  memset (cc, 0, sizeof (memif_msg_queue_elt_t));
+  memset (&conn, 0, sizeof (memif_connection_t));
+
+  cc->fd = 5;
+  cc->conn = &conn;
+  cc->sock = memif_socket;
+  TAILQ_INIT (&cc->msg_queue);
+
+  conn.args.interface_id = 11;
+  conn.args.mode = 1;
+  conn.args.socket = memif_socket;
+  strlcpy ((char *) conn.args.secret, MEMIF_TEST_SECRET,
+	   sizeof (MEMIF_TEST_SECRET));
+  strlcpy ((char *) conn.args.interface_name, MEMIF_TEST_IF_NAME,
+	   sizeof (MEMIF_TEST_IF_NAME));
+
+  memif_socket_t *ms = (memif_socket_t *) memif_socket;
+  memif_msg_enq_disconnect (cc, "TEST", 5);
+
+  e = TAILQ_FIRST (&cc->msg_queue);
+  memif_msg_disconnect_t h = e->msg.disconnect;
+
+  TEST_ASSERT_EQUAL_UINT16 (MEMIF_MSG_TYPE_DISCONNECT, e->msg.type);
+  TEST_ASSERT_EQUAL_INT (-1, e->fd);
+
+  TEST_ASSERT_EQUAL_INT (5, h.code);
+  TEST_ASSERT_EQUAL_STRING ("TEST", h.string);
+}
+
+TEST_GROUP_RUNNER (MemifSocket){ RUN_TEST_CASE (MemifSocket, CreateSocket)
+				   RUN_TEST_CASE (MemifSocket, DeleteSocket)
+
+}
+
+TEST_GROUP_RUNNER (MemifControlChannel)
+{
+  RUN_TEST_CASE (MemifControlChannel, EnqAck)
+  RUN_TEST_CASE (MemifControlChannel, EnqHello)
+  RUN_TEST_CASE (MemifControlChannel, EnqInit)
+  RUN_TEST_CASE (MemifControlChannel, EnqAddRegion)
+  RUN_TEST_CASE (MemifControlChannel, EnqAddRing)
+  RUN_TEST_CASE (MemifControlChannel, EnqConnect)
+  RUN_TEST_CASE (MemifControlChannel, EnqConnected)
+  RUN_TEST_CASE (MemifControlChannel, EnqDisconnect)
+}
+
+static void
+RunAllTests (void)
+{
+  RUN_TEST_GROUP (MemifSocket);
+  RUN_TEST_GROUP (MemifControlChannel);
+}
+
+int
+main (int argc, const char *argv[])
+{
+  return UnityMain (argc, argv, RunAllTests);
+}