@@ -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
new file mode 100644
@@ -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
+
new file mode 100644
@@ -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();
+}
new file mode 100644
@@ -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;
+};
@@ -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