From e8a05c6f1ac288a8cfa5b0837313fec8fb7aadaf Mon Sep 17 00:00:00 2001
From: Naoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>
Date: Mon, 4 Jul 2022 07:23:53 +0900
Subject: Add test case for librefop

The librefop aim to 100% code coverage testing.
This patch add test case with mock to aim to that criteria.

Bug-AGL: SPEC-4500

Signed-off-by: Naoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>
Change-Id: I4bf14d343b9fca784fb7bc3ee6d3e53691a5ea4e
---
 test/Makefile.am              |  60 +++++++
 test/file_util_test.cpp       |  84 +++++++++
 test/fileop_test_utils.cpp    | 275 ++++++++++++++++++++++++++++
 test/interface_test.cpp       | 409 ++++++++++++++++++++++++++++++++++++++++++
 test/interface_test_unit.cpp  | 199 ++++++++++++++++++++
 test/mock/libpthread_mock.hpp |  93 ++++++++++
 test/mock/libsystemd_mock.hpp | 208 +++++++++++++++++++++
 test/mock/syscall_io_mock.hpp | 156 ++++++++++++++++
 8 files changed, 1484 insertions(+)
 create mode 100644 test/Makefile.am
 create mode 100644 test/file_util_test.cpp
 create mode 100644 test/fileop_test_utils.cpp
 create mode 100644 test/interface_test.cpp
 create mode 100644 test/interface_test_unit.cpp
 create mode 100644 test/mock/libpthread_mock.hpp
 create mode 100644 test/mock/libsystemd_mock.hpp
 create mode 100644 test/mock/syscall_io_mock.hpp

diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..050390e
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,60 @@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+
+bin_PROGRAMS = \
+	interface_test interface_test_unit \
+	fileop_test_utils \
+	file_util_test
+
+interface_test_SOURCES = \
+	interface_test.cpp \
+	../lib/static-configurator.c \
+	../lib/file-util.c \
+	../lib/fileop.c
+
+interface_test_unit_SOURCES = \
+	interface_test_unit.cpp \
+	../lib/static-configurator.c \
+	../lib/file-util.c \
+	../lib/fileop.c
+
+fileop_test_utils_SOURCES = \
+	fileop_test_utils.cpp \
+	../lib/static-configurator.c \
+	../lib/file-util.c
+
+file_util_test_SOURCES = \
+	file_util_test.cpp
+
+# options
+# Additional library
+LDADD = \
+	-lrt -lpthread \
+	@GTEST_MAIN_LIBS@ \
+	@GMOCK_MAIN_LIBS@
+
+interface_test_LDADD = \
+	${LDADD}
+
+# C compiler options
+CFLAGS = \
+	-g \
+	-fsanitize=address -coverage \
+	-I$(top_srcdir)/lib \
+	-I$(top_srcdir)/include \
+	-D_GNU_SOURCE
+
+# C++ compiler options
+CXXFLAGS = \
+	-g \
+	-std=c++11 -fno-exceptions \
+	-fsanitize=address -coverage \
+	-I$(top_srcdir)/lib \
+	-I$(top_srcdir)/include \
+	-D_GNU_SOURCE
+
+# Linker options
+LDFLAGS =
+
+
+CLEANFILES = *.gcda *.gcno
diff --git a/test/file_util_test.cpp b/test/file_util_test.cpp
new file mode 100644
index 0000000..f78fbe2
--- /dev/null
+++ b/test/file_util_test.cpp
@@ -0,0 +1,84 @@
+/**
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * @file	data-pool-service-test.c
+ * @brief	Unit test fot data-pool-service-test.c
+ */
+#include <gtest/gtest.h>
+#include "mock/syscall_io_mock.hpp"
+
+// Test Terget files ---------------------------------------
+extern "C" {
+#include "../lib/file-util.c"
+}
+// Test Terget files ---------------------------------------
+using namespace ::testing;
+
+struct file_util_test : Test, SyscallIOMockBase {};
+
+//--------------------------------------------------------------------------------------------------------
+TEST_F(file_util_test, file_util_test_safe_read__success)
+{
+	ssize_t ret = -1;
+	uint8_t buffer[1024*1024];
+	size_t sz = 1024*1024;
+	size_t sza = sz - 1024;
+	size_t szb = 1024;
+
+	EXPECT_CALL(sysiom, read(1,buffer,sz)).WillOnce(SetErrnoAndReturn(EIO, -1));
+	ret = safe_read(1, buffer, sz);
+	ASSERT_EQ(-1, ret);
+
+	EXPECT_CALL(sysiom, read(1,buffer,sz)).WillOnce(Return(sz));
+	ret = safe_read(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, read(1,buffer,sz))
+		.WillOnce(SetErrnoAndReturn(EINTR, -1))
+		.WillOnce(Return(sz));
+	ret = safe_read(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, read(1,buffer,sz)).WillOnce(Return(sza));
+	EXPECT_CALL(sysiom, read(1,(&buffer[sza]),szb)).WillOnce(Return(szb));
+	ret = safe_read(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, read(1,buffer,sz)).WillOnce(Return(sza));
+	EXPECT_CALL(sysiom, read(1,(&buffer[sza]),szb)).WillOnce(Return(0));
+	ret = safe_read(1, buffer, sz);
+	ASSERT_EQ(sza, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(file_util_test, file_util_test_safe_write__success)
+{
+	ssize_t ret = -1;
+	uint8_t buffer[1024*1024];
+	size_t sz = 1024*1024;
+	size_t sza = sz - 1024;
+	size_t szb = 1024;
+
+	EXPECT_CALL(sysiom, write(1,buffer,sz)).WillOnce(SetErrnoAndReturn(EIO, -1));
+	ret = safe_write(1, buffer, sz);
+	ASSERT_EQ(-1, ret);
+
+	EXPECT_CALL(sysiom, write(1,buffer,sz)).WillOnce(Return(sz));
+	ret = safe_write(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, write(1,buffer,sz))
+		.WillOnce(SetErrnoAndReturn(EINTR, -1))
+		.WillOnce(Return(sz));
+	ret = safe_write(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, write(1,buffer,sz)).WillOnce(Return(sza));
+	EXPECT_CALL(sysiom, write(1,(&buffer[sza]),szb)).WillOnce(Return(szb));
+	ret = safe_write(1, buffer, sz);
+	ASSERT_EQ(sz, ret);
+
+	EXPECT_CALL(sysiom, write(1,buffer,sz)).WillOnce(Return(sza));
+	EXPECT_CALL(sysiom, write(1,(&buffer[sza]),szb)).WillOnce(Return(0));
+	ret = safe_write(1, buffer, sz);
+	ASSERT_EQ(sza, ret);
+}
diff --git a/test/fileop_test_utils.cpp b/test/fileop_test_utils.cpp
new file mode 100644
index 0000000..ca2f6dd
--- /dev/null
+++ b/test/fileop_test_utils.cpp
@@ -0,0 +1,275 @@
+/**
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * @file	data-pool-service-test.c
+ * @brief	Unit test fot data-pool-service-test.c
+ */
+#include <gtest/gtest.h>
+#include "mock/syscall_io_mock.hpp"
+
+// Test Terget files ---------------------------------------
+extern "C" {
+#include "../lib/fileop.c"
+}
+// Test Terget files ---------------------------------------
+using namespace ::testing;
+
+struct fileop_test_utils : Test, SyscallIOMockBase {};
+//struct data_pool_test_set_get_others : Test {};
+
+//--------------------------------------------------------------------------------------------------------
+TEST_F(fileop_test_utils, fileop_test_utils_refop_header_create__success)
+{
+	s_refop_file_header header;
+	s_refop_file_header *head = &header;
+
+	refop_header_create(head, 0, 0);
+	refop_header_create(head, 0x1234, 1*1024*1024*1024);
+	refop_header_create(head, 0x5678, 64*1024*1024*1024ul);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(fileop_test_utils, fileop_test_utils_refop_header_validation__invalid_header)
+{
+	s_refop_file_header header;
+	s_refop_file_header *head = &header;
+	int ret = -1;
+
+	// broaken magic
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	head->magic = 0;
+	ret = refop_header_validation(head);
+	ASSERT_EQ(-1, ret);
+
+	// broaken version
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	head->version = 0x88888888;
+	head->version_inv = 0x88888888;
+	ret = refop_header_validation(head);
+	ASSERT_EQ(-1, ret);
+
+	// invalid version
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	head->version = 0x88888888;
+	head->version_inv = ~head->version;
+	ret = refop_header_validation(head);
+	ASSERT_EQ(-1, ret);
+
+	// broaken crc
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	head->crc16 = 0x8888;
+	head->crc16_inv = 0x8888;
+	ret = refop_header_validation(head);
+	ASSERT_EQ(-1, ret);
+
+	// broaken size
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	head->size_inv = head->size;
+	ret = refop_header_validation(head);
+	ASSERT_EQ(-1, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(fileop_test_utils, fileop_test_utils_refop_header_validation__valid_header)
+{
+	s_refop_file_header header;
+	s_refop_file_header *head = &header;
+	int ret = -1;
+
+	// Valid header
+	refop_header_create(head, 0x1234, 64*1024*1024);
+	ret = refop_header_validation(head);
+	ASSERT_EQ(0, ret);
+
+	// Valid header
+	refop_header_create(head, 0xabcd, 64*1024);
+	ret = refop_header_validation(head);
+	ASSERT_EQ(0, ret);
+
+	// Valid header
+	refop_header_create(head, 0x0000, 1*1024*1024);
+	ret = refop_header_validation(head);
+	ASSERT_EQ(0, ret);
+
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(fileop_test_utils, fileop_test_utils_refop_file_test__stat_error)
+{
+	int ret = -1;
+
+	//dummy data
+	char testfilename[] = "/tmp/test.bin";
+
+	/* stat error case
+		EACCES
+		EFAULT
+		ELOOP
+		ENAMETOOLONG
+		ENOENT
+		ENOMEM
+		ENOTDIR
+		EOVERFLOW
+	*/
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(ENOENT, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-1, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(EACCES, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(EFAULT, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(ELOOP, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(ENAMETOOLONG, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(ENOMEM, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(ENOTDIR, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(SetErrnoAndReturn(EOVERFLOW, -1));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(-2, ret);
+
+	EXPECT_CALL(sysiom, stat(testfilename, _)).WillOnce(Return(0));
+	ret = refop_file_test(testfilename);
+	ASSERT_EQ(0, ret);
+}
+
+#if 0
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__stat_error)
+{
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+	
+	//dummy data
+	char directry[] = "/tmp";
+	char file[] = "test.bin";
+
+	/* stat error case
+		EACCES
+		EFAULT
+		ELOOP
+		ENAMETOOLONG
+		ENOENT
+		ENOMEM
+		ENOTDIR
+		EOVERFLOW
+	*/
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EACCES, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EFAULT, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ELOOP, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENAMETOOLONG, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOENT, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOMEM, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOTDIR, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EOVERFLOW, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__pathcheck_error)
+{
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+	
+	//dummy data
+	char directry[PATH_MAX];
+	char file[PATH_MAX];
+
+	memset(directry,0,sizeof(directry));
+	memset(file,0,sizeof(file));
+
+	//short directry string
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	//short file string
+	strncpy(directry,"/tmp",PATH_MAX);
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	// too long path
+	for(int i=1;i < (PATH_MAX-1);i++)
+		directry[i] = 'd';
+	strncpy(file,"test.bin",PATH_MAX);
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__success)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+	
+	//dummy data
+	char directry[] = "/tmp";
+	char directry2[] = "/tmp/";
+	char file[] = "test.bin";
+	char resultstr[] = "/tmp/test.bin";
+	char resultstr_bk1[] = "/tmp/test.bin.bk1";
+	char resultstr_new[] = "/tmp/test.bin.tmp";
+
+	//short directry string
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	//data check
+	hndl = (struct refop_halndle *)handle;
+	ASSERT_EQ(0, strcmp(hndl->latestfile,resultstr));
+	ASSERT_EQ(0, strcmp(hndl->backupfile1,resultstr_bk1));
+	ASSERT_EQ(0, strcmp(hndl->newfile,resultstr_new));
+	ASSERT_EQ(0, strcmp(hndl->basedir,directry2));
+	free(handle);
+
+	//short file string
+	EXPECT_CALL(sysiom, stat(directry2, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry2, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	//data check
+	hndl = (struct refop_halndle *)handle;
+	ASSERT_EQ(0, strcmp(hndl->latestfile,resultstr));
+	ASSERT_EQ(0, strcmp(hndl->backupfile1,resultstr_bk1));
+	ASSERT_EQ(0, strcmp(hndl->newfile,resultstr_new));
+	ASSERT_EQ(0, strcmp(hndl->basedir,directry2));
+	free(handle);
+}
+//--------------------------------------------------------------------------------------------------------
+#endif
diff --git a/test/interface_test.cpp b/test/interface_test.cpp
new file mode 100644
index 0000000..dec50bc
--- /dev/null
+++ b/test/interface_test.cpp
@@ -0,0 +1,409 @@
+/**
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * @file	interface_test.cpp
+ * @brief	Public interface test fot refop
+ */
+#include <gtest/gtest.h>
+
+// Test Terget files ---------------------------------------
+extern "C" {
+#include "../lib/libredundancyfileop.c"
+}
+// Test Terget files ---------------------------------------
+using namespace ::testing;
+
+struct interface_test : Test {};
+
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_set_redundancy_data__success)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp/refop-test/";
+	char file[] = "test.bin";
+	uint8_t *pbuf = NULL;
+	int64_t sz = 1 * 1024 * 1024;
+
+	(void)mkdir(directry, 0777);
+
+	pbuf = (uint8_t*)malloc(sz);
+
+	//short directry string
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0xff,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0xa5,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0x5a,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	free(pbuf);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_get_redundancy_data__success)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp/refop-test/";
+	char file[] = "test.bin";
+	uint8_t *pbuf = NULL;
+	int64_t sz = 1 * 1024 * 1024;
+	int64_t szr = 0;
+
+	(void)mkdir(directry, 0777);
+
+	pbuf = (uint8_t*)malloc(sz);
+
+	//short directry string
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_get_redundancy_data(handle, pbuf, sz, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz, szr);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	free(pbuf);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_set_and_get)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp/refop-test/";
+	char file[] = "test.bin";
+	char newfile[] = "/tmp/refop-test/test.bin.tmp";
+	char latestfile[] = "/tmp/refop-test/test.bin";
+	char backupfile[] = "/tmp/refop-test/test.bin.bk1";
+
+	uint8_t *pbuf = NULL;
+	uint8_t *prbuf = NULL;
+	int64_t sz = 64 * 1024;
+	int64_t szr = 0;
+	int checker = 0;
+
+	(void)mkdir(directry, 0777);
+
+	pbuf = (uint8_t*)malloc(sz);
+	prbuf = (uint8_t*)malloc(sz);
+
+	//short directry string
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0xff,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// Operation algorithm
+	//     Current                 Next
+	//    | latest | backup |     | latest | backup |
+	// a1 |    1   |   2    |     |  new   |    1   |
+	// a2 |    1   |   x    |     |  new   |    1   |
+	// a3 |    x   |   2    |     |  new   |    2   |
+	// a4 |    x   |   x    |     |  new   |    x   |
+
+	// a1
+	ret = refop_get_redundancy_data(handle, prbuf, sz, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xff);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa1,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+
+	// a2
+	unlink(backupfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa2,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a3
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz, &szr);
+	ASSERT_EQ(REFOP_RECOVER, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa3,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a4
+	unlink(backupfile);
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz, &szr);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	memset(pbuf,0xa4,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_remove_redundancy_data(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	free(pbuf);
+	free(prbuf);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_set_and_get_smallread)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp/refop-test/";
+	char file[] = "test.bin";
+	char newfile[] = "/tmp/refop-test/test.bin.tmp";
+	char latestfile[] = "/tmp/refop-test/test.bin";
+	char backupfile[] = "/tmp/refop-test/test.bin.bk1";
+
+	uint8_t *pbuf = NULL;
+	uint8_t *prbuf = NULL;
+	int64_t sz = 4 * 1024;
+	int64_t szr = 0;
+	int checker = 0;
+
+	(void)mkdir(directry, 0777);
+
+	pbuf = (uint8_t*)malloc(sz);
+	prbuf = (uint8_t*)malloc(sz);
+
+	//short directry string
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0xff,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// Operation algorithm
+	//     Current                 Next
+	//    | latest | backup |     | latest | backup |
+	// a1 |    1   |   2    |     |  new   |    1   |
+	// a2 |    1   |   x    |     |  new   |    1   |
+	// a3 |    x   |   2    |     |  new   |    2   |
+	// a4 |    x   |   x    |     |  new   |    x   |
+
+	// a1
+	ret = refop_get_redundancy_data(handle, prbuf, sz/2, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz/2, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xff);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa1,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+
+	// a2
+	unlink(backupfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz/2, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz/2, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa2,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a3
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz/2, &szr);
+	ASSERT_EQ(REFOP_RECOVER, ret);
+	ASSERT_EQ(sz/2, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa3,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a4
+	unlink(backupfile);
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz/2, &szr);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	memset(pbuf,0xa4,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_remove_redundancy_data(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	free(pbuf);
+	free(prbuf);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_set_and_get_largeread)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp/refop-test/";
+	char file[] = "test.bin";
+	char newfile[] = "/tmp/refop-test/test.bin.tmp";
+	char latestfile[] = "/tmp/refop-test/test.bin";
+	char backupfile[] = "/tmp/refop-test/test.bin.bk1";
+
+	uint8_t *pbuf = NULL;
+	uint8_t *prbuf = NULL;
+	int64_t sz = 256 * 1024;
+	int64_t szr = 0;
+	int checker = 0;
+
+	(void)mkdir(directry, 0777);
+
+	pbuf = (uint8_t*)malloc(sz);
+	prbuf = (uint8_t*)malloc(sz);
+
+	//short directry string
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	memset(pbuf,0xff,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// Operation algorithm
+	//     Current                 Next
+	//    | latest | backup |     | latest | backup |
+	// a1 |    1   |   2    |     |  new   |    1   |
+	// a2 |    1   |   x    |     |  new   |    1   |
+	// a3 |    x   |   2    |     |  new   |    2   |
+	// a4 |    x   |   x    |     |  new   |    x   |
+
+	// a1
+	ret = refop_get_redundancy_data(handle, prbuf, sz*2, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xff);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa1,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+
+	// a2
+	unlink(backupfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz*2, &szr);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa2,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a3
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz*2, &szr);
+	ASSERT_EQ(REFOP_RECOVER, ret);
+	ASSERT_EQ(sz, szr);
+	for(int i=0;i < szr;i++) {
+		checker += (prbuf[i] - (uint8_t)0xa1);
+	}
+	ASSERT_EQ(0, checker);
+
+	memset(pbuf,0xa3,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	// a4
+	unlink(backupfile);
+	unlink(latestfile);
+	ret = refop_get_redundancy_data(handle, prbuf, sz*2, &szr);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	memset(pbuf,0xa4,sz);
+	ret = refop_set_redundancy_data(handle, pbuf, sz);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_remove_redundancy_data(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	free(pbuf);
+	free(prbuf);
+}
+//--------------------------------------------------------------------------------------------------------
diff --git a/test/interface_test_unit.cpp b/test/interface_test_unit.cpp
new file mode 100644
index 0000000..b9e8df1
--- /dev/null
+++ b/test/interface_test_unit.cpp
@@ -0,0 +1,199 @@
+/**
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * @file	data-pool-service-test.c
+ * @brief	Unit test fot data-pool-service-test.c
+ */
+#include <gtest/gtest.h>
+#include "mock/syscall_io_mock.hpp"
+
+// Test Terget files ---------------------------------------
+extern "C" {
+#include "../lib/libredundancyfileop.c"
+}
+// Test Terget files ---------------------------------------
+using namespace ::testing;
+
+struct interface_test : Test, SyscallIOMockBase {};
+
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__arg_error)
+{
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp";
+	char file[] = "test.bin";
+
+	ret = refop_create_redundancy_handle(NULL, NULL, NULL);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_create_redundancy_handle(&handle, NULL, NULL);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_create_redundancy_handle(NULL, directry, NULL);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_create_redundancy_handle(&handle, directry, NULL);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_create_redundancy_handle(&handle, NULL, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_create_redundancy_handle(NULL, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__stat_error)
+{
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp";
+	char file[] = "test.bin";
+
+	/* stat error case
+		EACCES
+		EFAULT
+		ELOOP
+		ENAMETOOLONG
+		ENOENT
+		ENOMEM
+		ENOTDIR
+		EOVERFLOW
+	*/
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EACCES, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EFAULT, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ELOOP, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENAMETOOLONG, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOENT, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOMEM, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(ENOTDIR, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_NOENT, ret);
+
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(SetErrnoAndReturn(EOVERFLOW, -1));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SYSERROR, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__pathcheck_error)
+{
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[PATH_MAX];
+	char file[PATH_MAX];
+
+	memset(directry,0,sizeof(directry));
+	memset(file,0,sizeof(file));
+
+	//short directry string
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	//short file string
+	strncpy(directry,"/tmp",PATH_MAX);
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	// too long path
+	for(int i=1;i < (PATH_MAX-1);i++)
+		directry[i] = 'd';
+	strncpy(file,"test.bin",PATH_MAX);
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_create_redundancy_handle__success)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp";
+	char directry2[] = "/tmp/";
+	char file[] = "test.bin";
+	char resultstr[] = "/tmp/test.bin";
+	char resultstr_bk1[] = "/tmp/test.bin.bk1";
+	char resultstr_new[] = "/tmp/test.bin.tmp";
+
+	//short directry string
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	//data check
+	hndl = (struct refop_halndle *)handle;
+	ASSERT_EQ(0, strcmp(hndl->latestfile,resultstr));
+	ASSERT_EQ(0, strcmp(hndl->backupfile1,resultstr_bk1));
+	ASSERT_EQ(0, strcmp(hndl->newfile,resultstr_new));
+	ASSERT_EQ(0, strcmp(hndl->basedir,directry2));
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	//short file string
+	EXPECT_CALL(sysiom, stat(directry2, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry2, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+	//data check
+	hndl = (struct refop_halndle *)handle;
+	ASSERT_EQ(0, strcmp(hndl->latestfile,resultstr));
+	ASSERT_EQ(0, strcmp(hndl->backupfile1,resultstr_bk1));
+	ASSERT_EQ(0, strcmp(hndl->newfile,resultstr_new));
+	ASSERT_EQ(0, strcmp(hndl->basedir,directry2));
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+}
+//--------------------------------------------------------------------------------------------------------
+TEST_F(interface_test, interface_test_refop_release_redundancy_handle__all)
+{
+	struct refop_halndle *hndl;
+	refop_error_t ret = REFOP_SUCCESS;
+	refop_handle_t handle = NULL;
+
+	//dummy data
+	char directry[] = "/tmp";
+	char directry2[] = "/tmp/";
+	char file[] = "test.bin";
+	char resultstr[] = "/tmp/test.bin";
+	char resultstr_bk1[] = "/tmp/test.bin.bk1";
+	char resultstr_new[] = "/tmp/test.bin.tmp";
+
+	//short directry string
+	EXPECT_CALL(sysiom, stat(directry, _)).WillOnce(Return(0));
+	ret = refop_create_redundancy_handle(&handle, directry, file);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+
+	ret = refop_release_redundancy_handle(NULL);
+	ASSERT_EQ(REFOP_ARGERROR, ret);
+
+	ret = refop_release_redundancy_handle(handle);
+	ASSERT_EQ(REFOP_SUCCESS, ret);
+}
+//--------------------------------------------------------------------------------------------------------
diff --git a/test/mock/libpthread_mock.hpp b/test/mock/libpthread_mock.hpp
new file mode 100644
index 0000000..61ce43c
--- /dev/null
+++ b/test/mock/libpthread_mock.hpp
@@ -0,0 +1,93 @@
+#include <gmock/gmock.h>
+#include <functional>
+
+#include <signal.h>
+
+/*
+int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
+*/
+static std::function<int(int how, const sigset_t *set, sigset_t *oldset)> _pthread_sigmask;
+
+/*
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+int pthread_mutex_trylock(pthread_mutex_t *mutex);
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+
+static std::function<int(pthread_mutex_t *mutex)> _pthread_mutex_lock;
+static std::function<int(pthread_mutex_t *mutex)> _pthread_mutex_trylock;
+static std::function<int(pthread_mutex_t *mutex)> _pthread_mutex_unlock;
+*/
+
+class LibpthreadMocker {
+public:
+	LibpthreadMocker() {
+		_pthread_sigmask = [this](int how, const sigset_t *set, sigset_t *oldset)
+		{
+			return pthread_sigmask(how, set, oldset);
+		};
+
+/*
+		_pthread_mutex_lock = [this](pthread_mutex_t *mutex)
+		{
+			return pthread_mutex_lock(mutex);
+		};
+		_pthread_mutex_trylock = [this](pthread_mutex_t *mutex)
+		{
+			return pthread_mutex_trylock(mutex);
+		};
+		_pthread_mutex_unlock = [this](pthread_mutex_t *mutex)
+		{
+			return pthread_mutex_unlock(mutex);
+		};
+*/
+    }
+
+	~LibpthreadMocker() {
+		_pthread_sigmask = {};
+
+/*
+		_pthread_mutex_lock = {};
+		_pthread_mutex_trylock = {};
+		_pthread_mutex_unlock = {};
+*/
+    }
+
+	MOCK_CONST_METHOD3(pthread_sigmask, int(int how, const sigset_t *set, sigset_t *oldset));
+/*
+	MOCK_CONST_METHOD1(pthread_mutex_lock, int(pthread_mutex_t *mutex));
+	MOCK_CONST_METHOD1(pthread_mutex_trylock, int(pthread_mutex_t *mutex));
+	MOCK_CONST_METHOD1(pthread_mutex_unlock, int(pthread_mutex_t *mutex));
+*/
+};
+
+class LibpthreadMockBase {
+protected:
+   LibpthreadMocker lpm;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+    return _pthread_sigmask(how, set, oldset);
+}
+
+/*
+static int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+	return _pthread_mutex_lock(mutex);
+}
+static int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+	return _pthread_mutex_trylock(mutex);
+}
+static int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+	return _pthread_mutex_unlock(mutex);
+}
+*/
+#ifdef __cplusplus
+}
+#endif
diff --git a/test/mock/libsystemd_mock.hpp b/test/mock/libsystemd_mock.hpp
new file mode 100644
index 0000000..34de9a0
--- /dev/null
+++ b/test/mock/libsystemd_mock.hpp
@@ -0,0 +1,208 @@
+#include <gmock/gmock.h>
+#include <functional>
+
+#include <systemd/sd-event.h>
+
+
+/*
+int sd_event_add_signal(sd_event *event, sd_event_source **source,
+			int signal, sd_event_signal_handler_t handler, void *userdata);
+*/
+static std::function<int(sd_event *event, sd_event_source **source,
+			int signal, sd_event_signal_handler_t handler, void *userdata)> _sd_event_add_signal;
+
+/*
+int sd_event_add_io(sd_event *event, sd_event_source **source, int fd,
+			uint32_t events, sd_event_io_handler_t handler, void *userdata);
+int sd_event_source_get_io_fd(sd_event_source *source);
+int sd_event_source_set_io_fd_own(sd_event_source *source, int b);
+*/
+static std::function<int(sd_event *event, sd_event_source **source, int fd,
+			uint32_t events, sd_event_io_handler_t handler, void *userdata)>
+			_sd_event_add_io;
+static std::function<int(sd_event_source *source)> _sd_event_source_get_io_fd;
+static std::function<int(sd_event_source *source, int b)> _sd_event_source_set_io_fd_own;
+
+
+/*
+int sd_event_source_set_time(sd_event_source *source, uint64_t usec);
+int sd_event_now(sd_event *event, clockid_t clock, uint64_t *usec);
+int sd_event_add_time(	sd_event *event,
+ 	sd_event_source **source,
+ 	clockid_t clock,
+ 	uint64_t usec,
+ 	uint64_t accuracy,
+ 	sd_event_time_handler_t handler,
+ 	void *userdata);
+int sd_event_source_set_enabled(sd_event_source *source, int enabled);
+*/
+static std::function<int(sd_event_source *source, uint64_t usec)> _sd_event_source_set_time;
+static std::function<int(sd_event *event, clockid_t clock, uint64_t *usec)> _sd_event_now;
+static std::function<int(sd_event *event, sd_event_source **source, clockid_t clock,
+ 	uint64_t usec, uint64_t accuracy, sd_event_time_handler_t handler, void *userdata)> _sd_event_add_time;
+static std::function<int(sd_event_source *source, int enabled)> _sd_event_source_set_enabled;
+
+
+/*
+sd_event_source* sd_event_source_unref(sd_event_source *source);
+sd_event_source* sd_event_source_ref(sd_event_source *source);
+sd_event_source* sd_event_source_disable_unref(sd_event_source *source);
+*/
+static std::function<sd_event_source*(sd_event_source *source)> _sd_event_source_unref;
+static std::function<sd_event_source*(sd_event_source *source)> _sd_event_source_ref;
+static std::function<sd_event_source*(sd_event_source *source)> _sd_event_source_disable_unref;
+
+
+class LibsystemdMocker {
+public:
+	LibsystemdMocker() {
+		_sd_event_add_signal
+			= [this](sd_event *event, sd_event_source **source, int signal,
+						sd_event_signal_handler_t handler, void *userdata) {
+			return sd_event_add_signal(event, source, signal, handler, userdata);
+		};
+
+		_sd_event_add_io
+			= [this](sd_event *event, sd_event_source **source, int fd,
+						uint32_t events, sd_event_io_handler_t handler, void *userdata) {
+			return sd_event_add_io(event, source, fd, events, handler, userdata);
+		};
+		_sd_event_source_get_io_fd = [this](sd_event_source *source) {
+			return sd_event_source_get_io_fd(source);
+		};
+		_sd_event_source_set_io_fd_own = [this](sd_event_source *source, int b) {
+			return sd_event_source_set_io_fd_own(source, b);
+		};
+
+		_sd_event_source_set_time = [this](sd_event_source *source, uint64_t usec) {
+			return sd_event_source_set_time(source, usec);
+		};
+		_sd_event_now = [this](sd_event *event, clockid_t clock, uint64_t *usec) {
+			return sd_event_now(event, clock, usec);
+		};
+		_sd_event_add_time
+			= [this](sd_event *event, sd_event_source **source, clockid_t clock, uint64_t usec,
+					uint64_t accuracy, sd_event_time_handler_t handler, void *userdata) {
+			return sd_event_add_time(event, source, clock, usec, accuracy, handler, userdata);
+		};
+		_sd_event_source_set_enabled = [this](sd_event_source *source, int enabled) {
+			return sd_event_source_set_enabled(source, enabled);
+		};
+
+		_sd_event_source_unref = [this](sd_event_source *source) {
+			return sd_event_source_unref(source);
+		};
+		_sd_event_source_ref = [this](sd_event_source *source) {
+			return sd_event_source_ref(source);
+		};
+		_sd_event_source_disable_unref = [this](sd_event_source *source) {
+			return sd_event_source_disable_unref(source);
+		};
+	}
+
+	~LibsystemdMocker() {
+		_sd_event_add_signal = {};
+
+		_sd_event_add_io = {};
+		_sd_event_source_get_io_fd = {};
+		_sd_event_source_set_io_fd_own = {};
+
+		_sd_event_source_set_time = {};
+		_sd_event_now = {};
+		_sd_event_add_time = {};
+		_sd_event_source_set_enabled = {};
+
+		_sd_event_source_unref = {};
+		_sd_event_source_ref = {};
+		_sd_event_source_disable_unref = {};
+	}
+
+	MOCK_CONST_METHOD5(sd_event_add_signal, int(sd_event *event, sd_event_source **source, int signal, sd_event_signal_handler_t handler, void *userdata));
+
+	MOCK_CONST_METHOD6(sd_event_add_io, int(sd_event *event, sd_event_source **source, int fd, uint32_t events, sd_event_io_handler_t handler, void *userdata));
+	MOCK_CONST_METHOD1(sd_event_source_get_io_fd, int(sd_event_source *source));
+	MOCK_CONST_METHOD2(sd_event_source_set_io_fd_own, int(sd_event_source *source, int b));
+
+	MOCK_CONST_METHOD2(sd_event_source_set_time, int(sd_event_source *source, uint64_t usec));
+	MOCK_CONST_METHOD3(sd_event_now, int(sd_event *event, clockid_t clock, uint64_t *usec));
+	MOCK_CONST_METHOD7(sd_event_add_time, int(sd_event *event,sd_event_source **source, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t handler, void *userdata));
+	MOCK_CONST_METHOD2(sd_event_source_set_enabled, int(sd_event_source *source, int enabled));
+
+	MOCK_CONST_METHOD1(sd_event_source_unref, sd_event_source*(sd_event_source *source));
+	MOCK_CONST_METHOD1(sd_event_source_ref, sd_event_source*(sd_event_source *source));
+	MOCK_CONST_METHOD1(sd_event_source_disable_unref, sd_event_source*(sd_event_source *source));
+};
+
+class LibsystemdMockBase {
+protected:
+   LibsystemdMocker lsm;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int sd_event_add_signal(	sd_event *event,
+ 	sd_event_source **source,
+ 	int signal,
+ 	sd_event_signal_handler_t handler,
+ 	void *userdata)
+{
+    return _sd_event_add_signal(event, source, signal, handler, userdata);
+}
+
+int sd_event_add_io(sd_event *event, sd_event_source **source, int fd,
+			uint32_t events, sd_event_io_handler_t handler, void *userdata)
+{
+	return _sd_event_add_io(event, source, fd, events, handler, userdata);
+}
+
+int sd_event_source_get_io_fd(	sd_event_source *source)
+{
+	return _sd_event_source_get_io_fd(source);
+}
+
+int sd_event_source_set_io_fd_own(sd_event_source *source, int b)
+{
+	return _sd_event_source_set_io_fd_own(source, b);
+}
+
+int sd_event_source_set_time(sd_event_source *source, uint64_t usec)
+{
+	return _sd_event_source_set_time(source, usec);
+}
+
+int sd_event_now(sd_event *event, clockid_t clock, uint64_t *usec)
+{
+	return _sd_event_now(event, clock, usec);
+}
+
+int sd_event_add_time(sd_event *event, sd_event_source **source, clockid_t clock, uint64_t usec,
+			uint64_t accuracy, sd_event_time_handler_t handler, void *userdata)
+{
+	return _sd_event_add_time(event, source, clock, usec, accuracy, handler, userdata);
+}
+
+int sd_event_source_set_enabled(sd_event_source *source, int enabled)
+{
+	return _sd_event_source_set_enabled(source, enabled);
+}
+
+sd_event_source* sd_event_source_unref(sd_event_source *source)
+{
+	return _sd_event_source_unref(source);
+}
+
+sd_event_source* sd_event_source_ref(sd_event_source *source)
+{
+	return _sd_event_source_ref(source);
+}
+
+sd_event_source* sd_event_source_disable_unref(sd_event_source *source)
+{
+	return _sd_event_source_disable_unref(source);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test/mock/syscall_io_mock.hpp b/test/mock/syscall_io_mock.hpp
new file mode 100644
index 0000000..75efdb1
--- /dev/null
+++ b/test/mock/syscall_io_mock.hpp
@@ -0,0 +1,156 @@
+#include <gmock/gmock.h>
+#include <functional>
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+ssize_t read(int fd, void *buf, size_t count);
+ssize_t write(int fd, const void *buf, size_t count);
+int close(int fd);
+*/
+static std::function<ssize_t(int fd, void *buf, size_t count)> _read;
+static std::function<ssize_t(int fd, const void *buf, size_t count)> _write;
+static std::function<int(int)> _close;
+
+/*
+int unlink(const char *pathname);
+int stat(const char *pathname, struct stat *buf);
+*/
+static std::function<int(const char *)> _unlink;
+static std::function<int(const char *pathname, struct stat *buf)> _stat;
+
+
+/*
+int socket(int socket_family, int socket_type, int protocol);
+int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
+int listen(int sockfd, int backlog);
+int accept4(int sockfd, struct sockaddr *addr,
+			socklen_t *addrlen, int flags);
+*/
+static std::function<int(int socket_family, int socket_type, int protocol)> _socket;
+static std::function<int(int sockfd, const struct sockaddr *addr,socklen_t addrlen)> _bind;
+static std::function<int(int sockfd, int backlog)> _listen;
+static std::function<int(int sockfd, struct sockaddr *addr,
+			socklen_t *addrlen, int flags)> _accept4;
+
+class SyscallIOMocker {
+public:
+	SyscallIOMocker() {
+		_read = [this](int fd, void *buf, size_t count) {
+			return read(fd, buf, count);
+		};
+		_write = [this](int fd, const void *buf, size_t count) {
+			return write(fd, buf, count);
+		};
+		_close = [this](int fd){
+			return close(fd);
+		};
+
+		_unlink = [this](const char *pathname){
+			return unlink(pathname);
+		};
+		_stat = [this](const char *pathname, struct stat *buf) {
+			return stat(pathname, buf);
+		};
+
+		_socket = [this](int socket_family, int socket_type, int protocol){
+			return socket(socket_family, socket_type, protocol);
+		};
+		_bind = [this](int sockfd, const struct sockaddr *addr,socklen_t addrlen){
+			return bind(sockfd, addr,addrlen);
+		};
+		_listen = [this](int sockfd, int backlog){
+			return listen(sockfd, backlog);
+		};
+		_accept4
+			= [this](int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
+			return accept4(sockfd, addr, addrlen, flags);
+		};
+	}
+
+	~SyscallIOMocker() {
+		_read = {};
+		_write = {};
+		_close = {};
+
+		_unlink = {};
+		_stat = {};
+
+		_socket = {};
+		_bind = {};
+		_listen = {};
+		_accept4 = {};
+	}
+
+	MOCK_CONST_METHOD3(read, ssize_t(int fd, void *buf, size_t count));
+	MOCK_CONST_METHOD3(write, ssize_t(int fd, const void *buf, size_t count));
+	MOCK_CONST_METHOD1(close, int(int));
+
+	MOCK_CONST_METHOD1(unlink, int(const char *));
+	MOCK_CONST_METHOD2(stat, int(const char *pathname, struct stat *buf));
+
+	MOCK_CONST_METHOD3(socket, int(int socket_family, int socket_type, int protocol));
+	MOCK_CONST_METHOD3(bind, int(int sockfd, const struct sockaddr *addr,socklen_t addrlen));
+	MOCK_CONST_METHOD2(listen, int(int sockfd, int backlog));
+	MOCK_CONST_METHOD4(accept4, int(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags));
+};
+
+class SyscallIOMockBase {
+protected:
+	SyscallIOMocker sysiom;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ssize_t read(int fd, void *buf, size_t count)
+{
+    return _read(fd, buf, count);
+}
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+    return _write(fd, buf, count);
+}
+
+int close(int fd)
+{
+    return _close(fd);
+}
+
+int unlink(const char *pathname)
+{
+	return _unlink(pathname);
+}
+
+int stat(const char *pathname, struct stat *buf)
+{
+	return _stat(pathname, buf);
+}
+
+int socket(int socket_family, int socket_type, int protocol)
+{
+	return _socket(socket_family, socket_type, protocol);
+}
+
+int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
+{
+	return _bind(sockfd, addr, addrlen);
+}
+
+int listen(int sockfd, int backlog)
+{
+	return _listen(sockfd, backlog);
+}
+
+int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+	return _accept4(sockfd, addr, addrlen, flags);
+}
+
+#ifdef __cplusplus
+}
+#endif
-- 
cgit