[dpdk-dev] [RFC 4/4] app/test-gtest: example google test application

Declan Doherty declan.doherty at intel.com
Tue Aug 2 22:37:49 CEST 2016


Adds a new application to demonstrate how google test could
be used as a new unit test framework.

To compile both ${GTEST_DIR} and ${GMOCK_DIR} the install paths to google
test and google mock directories respectively must be defined/exported.

Signed-off-by: Declan Doherty <declan.doherty at intel.com>
---
 app/Makefile                    |   1 +
 app/test-gtest/Makefile         |  67 ++++++++++
 app/test-gtest/main.cpp         |  20 +++
 app/test-gtest/test_mempool.cpp | 281 ++++++++++++++++++++++++++++++++++++++++
 config/common_base              |   5 +
 5 files changed, 374 insertions(+)
 create mode 100644 app/test-gtest/Makefile
 create mode 100644 app/test-gtest/main.cpp
 create mode 100644 app/test-gtest/test_mempool.cpp

diff --git a/app/Makefile b/app/Makefile
index 30ec292..71cf31e 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -38,5 +38,6 @@ DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
 DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
 DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump
+DIRS-$(CONFIG_RTE_TEST_GTEST) += test-gtest
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/test-gtest/Makefile b/app/test-gtest/Makefile
new file mode 100644
index 0000000..66dbe15
--- /dev/null
+++ b/app/test-gtest/Makefile
@@ -0,0 +1,67 @@
+#   BSD LICENSE
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ifneq ($(MAKECMDGOALS),clean)
+ifeq ($(GTEST_DIR),)
+$(error "Please define GTEST_DIR environment variable")
+endif
+
+ifeq ($(GMOCK_DIR),)
+$(error "Please define GMOCK_DIR environment variable")
+endif
+endif
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = test-gtest
+
+# all source are stored in SRCS-y
+SRCS-y := main.cpp
+SRCS-y += test_mempool.cpp
+
+CFLAGS += -O0
+CFLAGS += $(WERROR_FLAGS)
+
+CXXFLAGS += -std=c++11
+CXXFLAGS += -I$(GTEST_DIR)/include 
+CXXFLAGS += -I$(GMOCK_DIR)/include
+
+LDFLAGS += -lstdc++
+LDFLAGS += -L$(GMOCK_DIR) -lgmock
+
+# this application needs libraries first
+DEPDIRS-y += lib drivers
+
+include $(RTE_SDK)/mk/rte.app.mk
+
diff --git a/app/test-gtest/main.cpp b/app/test-gtest/main.cpp
new file mode 100644
index 0000000..a221823
--- /dev/null
+++ b/app/test-gtest/main.cpp
@@ -0,0 +1,20 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_eal.h>
+
+int main(int argc, char *argv[])
+{
+	/* Initialise DPDK EAL */
+	int ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	testing::InitGoogleMock(&argc, argv);
+	return RUN_ALL_TESTS();
+}	
diff --git a/app/test-gtest/test_mempool.cpp b/app/test-gtest/test_mempool.cpp
new file mode 100644
index 0000000..4c3f7e2
--- /dev/null
+++ b/app/test-gtest/test_mempool.cpp
@@ -0,0 +1,281 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_eal.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+
+class MemoryPool : public ::testing::Test {
+
+protected:
+
+	virtual void SetUp() {
+		mp = NULL;
+		mempool_elements = (rte_lcore_count() * (lcore_cache_size +
+				RTE_MEMPOOL_CACHE_MAX_SIZE) -1);
+	}
+
+	virtual void TearDown() {
+		if (mp)
+			rte_mempool_free(mp);
+
+	}
+
+	/*
+	 * save the object number in the first 4 bytes of object data. All
+	 * other bytes are set to 0.
+	 */
+	static void
+	obj_initializer_fn(struct rte_mempool *mp, void *arg __rte_unused,
+			void *obj, unsigned i)
+	{
+		uint32_t *objnum = (uint32_t *)obj;
+
+		memset(obj, 0, mp->elt_size);
+		*objnum = i;
+	}
+
+	struct rte_mempool *mp;
+
+	static const unsigned element_size = 2048;
+	static const uint32_t lcore_cache_size = 16;
+
+	unsigned mempool_elements;
+};
+
+TEST_F(MemoryPool, CreateWithNoCache)
+{
+	mp = rte_mempool_create("test_nocache", mempool_elements, element_size,
+			0, 0, NULL, NULL, obj_initializer_fn, NULL,
+			SOCKET_ID_ANY, 0);
+
+	ASSERT_NE(mp, (void *)NULL);
+
+	EXPECT_EQ(mp, rte_mempool_lookup("test_nocache"));
+	EXPECT_EQ(rte_mempool_avail_count(mp), mempool_elements);
+}
+
+TEST_F(MemoryPool, CreateWithCache)
+{
+	mp = rte_mempool_create("test_cache", mempool_elements, element_size,
+			RTE_MEMPOOL_CACHE_MAX_SIZE, 0, NULL, NULL,
+			obj_initializer_fn, NULL, SOCKET_ID_ANY, 0);
+
+	ASSERT_NE(mp, (void *)NULL);
+
+	EXPECT_EQ(mp, rte_mempool_lookup("test_cache"));
+	EXPECT_EQ(rte_mempool_avail_count(mp), mempool_elements);
+}
+
+TEST_F(MemoryPool, ExceedMaxCacheSize)
+{
+	mp = rte_mempool_create("test_exceed_max_cache_sz",
+			mempool_elements, element_size,
+			RTE_MEMPOOL_CACHE_MAX_SIZE + 1, 0, NULL, NULL,
+			obj_initializer_fn, NULL, SOCKET_ID_ANY, 0);
+
+	ASSERT_EQ(mp, (void *)NULL);
+}
+
+TEST_F(MemoryPool, MempoolNameCollosion) {
+	mp = rte_mempool_create("test_name_collosion", mempool_elements,
+			element_size, RTE_MEMPOOL_CACHE_MAX_SIZE, 0, NULL, NULL,
+			obj_initializer_fn, NULL, SOCKET_ID_ANY, 0);
+
+	ASSERT_NE(mp, (void *)NULL);
+
+	ASSERT_EQ(rte_mempool_create("test_name_collosion", mempool_elements,
+			element_size, RTE_MEMPOOL_CACHE_MAX_SIZE, 0, NULL, NULL,
+			obj_initializer_fn, NULL, SOCKET_ID_ANY, 0),
+			(struct rte_mempool *)NULL);
+}
+
+TEST_F(MemoryPool, ExternalMemorySize) {
+	size_t sz;
+	ssize_t usz;
+
+	uint32_t obj_size = rte_mempool_calc_obj_size(element_size, 0, NULL);
+
+	sz = rte_mempool_xmem_size(mempool_elements, obj_size,
+			MEMPOOL_PG_SHIFT_MAX);
+
+	usz = rte_mempool_xmem_usage(NULL, mempool_elements, obj_size, 0, 1,
+			MEMPOOL_PG_SHIFT_MAX);
+
+	EXPECT_EQ(sz, (size_t)usz);
+}
+
+
+class MempoolMock {
+public:
+
+	MOCK_METHOD2(MempoolInitializerMockFn,
+			void(struct rte_mempool *, void *));
+
+	MOCK_METHOD4(MempoolObjInitializerMockFn,
+			void(struct rte_mempool *, void *arg, void *, unsigned));
+
+	static MempoolMock *obj;
+
+	static void mempool_initializer_fn(struct rte_mempool *mp, void * arg)
+	{
+		obj->MempoolInitializerMockFn(mp, arg);
+	}
+
+	static void mempool_obj_initializer_fn(struct rte_mempool *mp,
+			void *arg, void *m_obj, unsigned i)
+	{
+		obj->MempoolObjInitializerMockFn(mp, arg, m_obj, i);
+	}
+};
+
+
+MempoolMock * MempoolMock::obj;
+
+TEST_F(MemoryPool, MempoolInitialization)
+{
+	MempoolMock mock;
+	MempoolMock::obj = &mock;
+
+
+	EXPECT_CALL(mock, MempoolInitializerMockFn(::testing::_, ::testing::_))
+		.Times(1);
+
+	EXPECT_CALL(mock, MempoolObjInitializerMockFn(
+			::testing::_, ::testing::_, ::testing::_, ::testing::_))
+			.Times(mempool_elements);
+
+	mp = rte_mempool_create("test_nocache", mempool_elements,
+			element_size, 0, 0,
+			MempoolMock::mempool_initializer_fn, NULL,
+			MempoolMock::mempool_obj_initializer_fn, NULL,
+			SOCKET_ID_ANY, 0);
+	ASSERT_NE(mp, (void *)NULL);
+
+	EXPECT_EQ(rte_mempool_full(mp), 1);
+}
+
+
+class MemoryPoolWithNoCache : public MemoryPool {
+protected :
+	virtual void SetUp() {
+		mempool_elements = (rte_lcore_count() * (lcore_cache_size +
+				RTE_MEMPOOL_CACHE_MAX_SIZE) -1);
+
+		objs = (void **)malloc(mempool_elements * sizeof(void *));
+
+		mp = rte_mempool_create("test_nocache", mempool_elements,
+				element_size, 0, 0, NULL, NULL,
+				obj_initializer_fn, NULL, SOCKET_ID_ANY, 0);
+		ASSERT_NE(mp, (void *)NULL);
+
+		EXPECT_EQ(rte_mempool_full(mp), 1);
+
+	}
+
+	virtual void TearDown() {
+		if (mp)
+			rte_mempool_free(mp);
+
+		if (objs)
+			free(objs);
+
+	}
+
+	void **objs;
+	int i;
+};
+
+TEST_F(MemoryPoolWithNoCache, GetOneObjectPutOneObject)
+{
+	/* Get an object for mempool */
+	ASSERT_EQ(rte_mempool_get(mp, &objs[0]), 0);
+
+	/* Verify object count in mempool */
+	EXPECT_EQ(rte_mempool_avail_count(mp), mempool_elements -1);
+
+	/* Verify physical address of an object */
+
+#ifndef RTE_EXEC_ENV_BSDAPP
+	/* rte_mem_virt2phy() not supported on BSD */
+	EXPECT_EQ(rte_mempool_virt2phy(mp, objs[0]), rte_mem_virt2phy(objs[0]));
+#endif
+
+	/* put the object back */
+	rte_mempool_put(mp, objs[0]);
+
+	EXPECT_EQ(rte_mempool_avail_count(mp), mempool_elements);
+}
+
+TEST_F(MemoryPoolWithNoCache, GetAllObjectsPutAllObjects)
+{
+	/* Get all objects from mempool */
+	for (i = 0; i < mempool_elements; i++) {
+		EXPECT_EQ(rte_mempool_get(mp, &objs[i]), 0);
+		/* Verify physical address of an object */
+#ifndef RTE_EXEC_ENV_BSDAPP
+		EXPECT_EQ(rte_mempool_virt2phy(mp, objs[i]),
+				rte_mem_virt2phy(objs[i]));
+#endif
+	}
+
+	/* Verify object count in mempool */
+	EXPECT_EQ(rte_mempool_avail_count(mp), 0);
+
+
+	/* Put the objects back */
+	for (i = 0; i < mempool_elements; i++) {
+		rte_mempool_put(mp, objs[i]);
+	}
+
+	EXPECT_EQ(rte_mempool_avail_count(mp), mempool_elements);
+}
+
+TEST_F(MemoryPoolWithNoCache, GetOjectFromEmptyMempool)
+{
+	void *err_obj = NULL;
+
+	for (i = 0; i < mempool_elements; i++)
+		EXPECT_EQ(rte_mempool_get(mp, &objs[i]), 0);
+
+	EXPECT_EQ(rte_mempool_empty(mp), 1);
+
+	EXPECT_LT(rte_mempool_get(mp, &err_obj), 0);
+	EXPECT_EQ(err_obj, (void *)NULL);
+
+	for (i = 0; i < mempool_elements; i++)
+		rte_mempool_put(mp, objs[i]);
+
+	EXPECT_EQ(rte_mempool_full(mp), 1);
+	// printf("test_mempool_basic_ex the mempool should be full\n");
+}
+
+
+
+class MemoryPoolSingleProducerSingleConsumer : public MemoryPool {
+protected:
+	virtual void SetUp() {
+		lcore_id = rte_lcore_id();
+
+		mempool_elements = (rte_lcore_count() * (lcore_cache_size +
+				RTE_MEMPOOL_CACHE_MAX_SIZE) -1);
+
+		mp = rte_mempool_create("single_producer_consumer",
+				mempool_elements, element_size, 0, 0,
+				NULL, NULL,
+				obj_initializer_fn, NULL,
+				SOCKET_ID_ANY,
+				MEMPOOL_F_NO_CACHE_ALIGN |
+				MEMPOOL_F_SP_PUT |
+				MEMPOOL_F_SC_GET);
+
+		ASSERT_NE(mp, (void *)NULL);
+
+		EXPECT_EQ(rte_mempool_full(mp), 1);
+	}
+
+	unsigned lcore_id, lcore_next;
+};
diff --git a/config/common_base b/config/common_base
index 7830535..6ef4de6 100644
--- a/config/common_base
+++ b/config/common_base
@@ -579,6 +579,11 @@ CONFIG_RTE_APP_TEST=y
 CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
 
 #
+# Compile the google test unit tests
+#
+CONFIG_RTE_TEST_GTEST=y
+
+#
 # Compile the PMD test application
 #
 CONFIG_RTE_TEST_PMD=y
-- 
2.5.5



More information about the dev mailing list