From b9f0ad28eca29ac350a6fb624030449aab9c2232 Mon Sep 17 00:00:00 2001 From: Paul Luse Date: Thu, 3 Aug 2017 10:21:48 -0700 Subject: [PATCH] ut/nvme: add coverage for nvme_driver_init() & new mock macro Change-Id: I1d62e34deed873446a9a87f16188b5c8ed21aea5 Signed-off-by: Paul Luse Reviewed-on: https://review.gerrithub.io/372551 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Daniel Verkamp --- include/spdk_internal/mock.h | 25 ++++++--- test/lib/test_env.c | 43 ++++++++------- test/unit/lib/nvme/nvme.c/nvme_ut.c | 82 ++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 27 deletions(-) diff --git a/include/spdk_internal/mock.h b/include/spdk_internal/mock.h index 35b15c8e44..aa3893af3e 100644 --- a/include/spdk_internal/mock.h +++ b/include/spdk_internal/mock.h @@ -38,14 +38,16 @@ /* used to signify pass through */ #define MOCK_PASS_THRU (0xdeadbeef) - +#define MOCK_PASS_THRU_P (void*)0xdeadbeef /* helper for initializing struct value with mock macros */ #define MOCK_STRUCT_INIT(...) \ { __VA_ARGS__ } -/* for controlling mocked function behavior, setting */ -/* and getting values from the stub, the _P macros are */ -/* for mocking functions that return pointer values */ +/* + * For controlling mocked function behavior, setting + * and getting values from the stub, the _P macros are + * for mocking functions that return pointer values. + */ #define MOCK_SET(fn, ret, val) \ ut_ ## fn = (ret)val @@ -75,9 +77,7 @@ } \ } -/* For defining the implmentation of stubs for SPDK funcs. */ -/* DEFINE_STUB_P macro is for stubs that return pointer values. */ -/* DEFINE_STUB_V macro is for void stubs. */ +/* DEFINE_STUB is for defining the implmentation of stubs for SPDK funcs. */ #define DEFINE_STUB(fn, ret, dargs, val) \ ret ut_ ## fn = val; \ ret fn dargs; \ @@ -86,6 +86,7 @@ return MOCK_GET(fn); \ } +/* DEFINE_STUB_P macro is for stubs that return pointer values */ #define DEFINE_STUB_P(fn, ret, dargs, val) \ ret ut_ ## fn = val; \ ret* ut_p_ ## fn = &(ut_ ## fn); \ @@ -95,12 +96,22 @@ return MOCK_GET_P(fn); \ } +/* DEFINE_STUB_V macro is for stubs that don't have a return value */ #define DEFINE_STUB_V(fn, dargs) \ void fn dargs; \ void fn dargs \ { \ } +/* DEFINE_STUB_VP macro is for stubs that return void pointer values */ +#define DEFINE_STUB_VP(fn, dargs, val) \ + void* ut_p_ ## fn = val; \ + void* fn dargs; \ + void* fn dargs \ + { \ + return MOCK_GET_P(fn); \ + } + /* declare wrapper protos (alphabetically please) here */ DECLARE_WRAPPER(calloc, void *, (size_t nmemb, size_t size)); diff --git a/test/lib/test_env.c b/test/lib/test_env.c index d649fa1265..4836272b65 100644 --- a/test/lib/test_env.c +++ b/test/lib/test_env.c @@ -49,6 +49,31 @@ * working with these functions. See /lib/ut_mock for details. */ +/* + * these stubs have a return value set with one of the MOCK_SET macros + */ +DEFINE_STUB(spdk_process_is_primary, bool, (void), true) + +DEFINE_STUB_VP(spdk_memzone_lookup, (const char *name), NULL) + +/* + * these mocks don't fit well with the library macro model because + * they do 'something' other than just return a pre-set value + */ + +/* setup the mock control to pass thru by default */ +void *ut_p_spdk_memzone_reserve = MOCK_PASS_THRU_P; +void * +spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) +{ + if (ut_p_spdk_memzone_reserve && + ut_p_spdk_memzone_reserve == MOCK_PASS_THRU_P) { + return malloc(len); + } else { + return ut_p_spdk_memzone_reserve; + } +} + void * spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) { @@ -116,18 +141,6 @@ uint64_t spdk_vtophys(void *buf) } } -void * -spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) -{ - return malloc(len); -} - -void * -spdk_memzone_lookup(const char *name) -{ - return NULL; -} - void spdk_memzone_dump(FILE *f) { @@ -179,12 +192,6 @@ spdk_mempool_count(const struct spdk_mempool *mp) return 1024; } -bool -spdk_process_is_primary(void) -{ - return true; -} - uint64_t ut_tsc = 0; uint64_t spdk_get_ticks(void) { diff --git a/test/unit/lib/nvme/nvme.c/nvme_ut.c b/test/unit/lib/nvme/nvme.c/nvme_ut.c index 320e9a7283..6a41620b60 100644 --- a/test/unit/lib/nvme/nvme.c/nvme_ut.c +++ b/test/unit/lib/nvme/nvme.c/nvme_ut.c @@ -37,10 +37,10 @@ #include "nvme/nvme.c" -#include "lib/test_env.c" - #include "spdk_internal/mock.h" +#include "lib/test_env.c" + DEFINE_STUB_V(nvme_ctrlr_fail, (struct spdk_nvme_ctrlr *ctrlr, bool hot_remove)) @@ -113,6 +113,82 @@ memset_trid(struct spdk_nvme_transport_id *trid1, struct spdk_nvme_transport_id memset(trid2, 0, sizeof(struct spdk_nvme_transport_id)); } +static void +test_nvme_driver_init(void) +{ + int rc; + struct nvme_driver dummy; + g_spdk_nvme_driver = &dummy; + + /* adjust this so testing doesn't take so long */ + g_nvme_driver_timeout_ms = 100; + + /* process is primary and mem already reserved */ + MOCK_SET(spdk_process_is_primary, bool, true); + dummy.initialized = true; + rc = nvme_driver_init(); + CU_ASSERT(rc == 0); + + /* + * Process is primary and mem not yet reserved but the call + * to spdk_memzone_reserve() returns NULL. + */ + g_spdk_nvme_driver = NULL; + MOCK_SET(spdk_process_is_primary, bool, true); + MOCK_SET_P(spdk_memzone_reserve, void *, NULL); + rc = nvme_driver_init(); + CU_ASSERT(rc == -1); + + /* process is not primary, no mem already reserved */ + MOCK_SET(spdk_process_is_primary, bool, false); + MOCK_SET_P(spdk_memzone_lookup, void *, NULL); + g_spdk_nvme_driver = NULL; + rc = nvme_driver_init(); + CU_ASSERT(rc == -1); + + /* process is not primary, mem is already reserved & init'd */ + MOCK_SET(spdk_process_is_primary, bool, false); + MOCK_SET_P(spdk_memzone_lookup, void *, &dummy); + dummy.initialized = true; + rc = nvme_driver_init(); + CU_ASSERT(rc == 0); + + /* process is not primary, mem is reserved but not intiialized */ + /* and times out */ + MOCK_SET(spdk_process_is_primary, bool, false); + MOCK_SET_P(spdk_memzone_reserve, void *, &dummy); + dummy.initialized = false; + rc = nvme_driver_init(); + CU_ASSERT(rc == -1); + + /* process is primary, got mem but mutex won't init */ + MOCK_SET(spdk_process_is_primary, bool, true); + MOCK_SET_P(spdk_memzone_reserve, void *, &dummy); + MOCK_SET(pthread_mutexattr_init, int, -1); + g_spdk_nvme_driver = NULL; + dummy.initialized = true; + rc = nvme_driver_init(); + /* for FreeBSD we can't can't effectively mock this path */ +#ifndef __FreeBSD__ + CU_ASSERT(rc != 0); +#else + CU_ASSERT(rc == 0); +#endif + + /* process is primary, got mem, mutex OK */ + MOCK_SET(spdk_process_is_primary, bool, true); + MOCK_SET(pthread_mutexattr_init, int, MOCK_PASS_THRU); + g_spdk_nvme_driver = NULL; + rc = nvme_driver_init(); + CU_ASSERT(g_spdk_nvme_driver->initialized == false); + CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->init_ctrlrs)); + CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->attached_ctrlrs)); + CU_ASSERT(rc == 0); + + g_spdk_nvme_driver = NULL; + MOCK_SET_P(spdk_memzone_reserve, void *, MOCK_PASS_THRU_P); +} + static void test_spdk_nvme_detach(void) { @@ -739,6 +815,8 @@ int main(int argc, char **argv) test_trid_adrfam_str) == NULL || CU_add_test(suite, "test_nvme_ctrlr_probe", test_nvme_ctrlr_probe) == NULL || + CU_add_test(suite, "test_nvme_driver_init", + test_nvme_driver_init) == NULL || CU_add_test(suite, "test_spdk_nvme_detach", test_spdk_nvme_detach) == NULL || CU_add_test(suite, "test_nvme_completion_poll_cb",