Commit 043d5411 authored by Paul Luse's avatar Paul Luse Committed by Daniel Verkamp
Browse files

tests: macro-ize the creation and use of wrappers and stubs



Includes macros for wrappers (for syscalls) and stubs
(for SPDK functions) including an example of syscall
wrapper as well as a stub with both pointer and non
pointer values.

Change-Id: I9b19d81d5b9cbf2bbb327f58dbf985b3b253e800
Signed-off-by: default avatarPaul Luse <paul.e.luse@intel.com>
Reviewed-on: https://review.gerrithub.io/366348


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent a9428cb3
Loading
Loading
Loading
Loading
+53 −4
Original line number Diff line number Diff line
@@ -36,15 +36,64 @@

#include "spdk/stdinc.h"

/* used to signify pass through */
#define MOCK_PASS_THRU (0xdeadbeef)

/* 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};

#define MOCK_SET_P(fn, ret, val) \
	ut_p_ ## fn = (ret){val};

#define MOCK_GET(fn) \
	ut_ ## fn

#define MOCK_GET_P(fn) \
	ut_p_ ## fn

/* for declaring function protoypes for wrappers */
#define DECLARE_WRAPPER(fn, ret, args) \
	extern ret ut_ ## fn; \
	ret __wrap_ ## fn args; ret __real_ ## fn args;

/* define new wrappers (alphabetically please) here using above helper macro */
extern int ut_fake_pthread_mutex_init;
/* for defining the implmentation of wrappers for syscalls */
#define DEFINE_WRAPPER(fn, ret, dargs, pargs, val) \
	ret ut_ ## fn = val; \
	ret __wrap_ ## fn dargs \
	{ \
		if (ut_ ## fn == (ret)MOCK_PASS_THRU) { \
			return __real_ ## fn pargs; \
		} else { \
			return MOCK_GET(fn); \
		} \
	}

/* for defining the implmentation of stubs for SPDK funcs */
/* the _P macro is for stubs that return pointer values */
#define DEFINE_STUB(fn, ret, dargs, val) \
	ret ut_ ## fn = val; \
	ret fn dargs; \
	ret fn dargs \
	{ \
		return MOCK_GET(fn); \
	}

#define DEFINE_STUB_P(fn, ret, dargs, val) \
	ret ut_ ## fn = val; \
	ret* ut_p_ ## fn = &(ut_ ## fn); \
	ret* fn dargs; \
	ret* fn dargs \
	{ \
		return MOCK_GET_P(fn); \
	}

/* declare wrapper protos (alphabetically please) here */
DECLARE_WRAPPER(pthread_mutex_init, int,
		(pthread_mutex_t *mtx, const pthread_mutexattr_t *attr));

extern int ut_fake_pthread_mutexattr_init;
DECLARE_WRAPPER(pthread_mutexattr_init, int,
		(pthread_mutexattr_t *attr));

+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

C_SRCS = spdk_mock.c
C_SRCS = mock.c
LIBNAME = spdk_mock

include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
+6 −21
Original line number Diff line number Diff line
@@ -31,26 +31,11 @@
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "spdk_internal/spdk_mock.h"
#include "spdk_internal/mock.h"

int ut_fake_pthread_mutex_init = 0;
int
__wrap_pthread_mutex_init(pthread_mutex_t *mtx, const pthread_mutexattr_t *attr)
{
	if (ut_fake_pthread_mutex_init == 0) {
		return __real_pthread_mutex_init(mtx, attr);
	} else {
		return ut_fake_pthread_mutex_init;
	}
}
DEFINE_WRAPPER(pthread_mutex_init, int,
	       (pthread_mutex_t *mtx, const pthread_mutexattr_t *attr),
	       (mtx, attr), MOCK_PASS_THRU)

int ut_fake_pthread_mutexattr_init = 0;
int
__wrap_pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
	if (ut_fake_pthread_mutexattr_init == 0) {
		return __real_pthread_mutexattr_init(attr);
	} else {
		return ut_fake_pthread_mutexattr_init;
	}
}
DEFINE_WRAPPER(pthread_mutexattr_init, int,
	       (pthread_mutexattr_t *attr), (attr), MOCK_PASS_THRU)
+62 −16
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@

#include "lib/test_env.c"

#include "spdk_internal/spdk_mock.h"
#include "spdk_internal/mock.h"

int
spdk_pci_nvme_enumerate(spdk_pci_enum_cb enum_cb, void *enum_ctx)
@@ -63,13 +63,6 @@ spdk_nvme_transport_available(enum spdk_nvme_transport_type trtype)
	return true;
}

struct spdk_nvme_ctrlr *nvme_transport_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
		const struct spdk_nvme_ctrlr_opts *opts,
		void *devhandle)
{
	return NULL;
}

int
nvme_transport_ctrlr_scan(const struct spdk_nvme_transport_id *trid,
			  void *cb_ctx,
@@ -153,19 +146,66 @@ memset_trid(struct spdk_nvme_transport_id *trid1, struct spdk_nvme_transport_id
	memset(trid2, 0, sizeof(struct spdk_nvme_transport_id));
}

DEFINE_STUB_P(nvme_transport_ctrlr_construct, struct spdk_nvme_ctrlr,
	      (const struct spdk_nvme_transport_id *trid,
	       const struct spdk_nvme_ctrlr_opts *opts,
	       void *devhandle), {0})

DEFINE_STUB(dummy_probe_cb, bool,
	    (void *cb_ctx, const struct spdk_nvme_transport_id *trid,
	     struct spdk_nvme_ctrlr_opts *opts), false)

static void
test_nvme_ctrlr_probe(void)
{
	int rc = 0;
	const struct spdk_nvme_transport_id *trid = NULL;
	void *devhandle = NULL;
	void *cb_ctx = NULL;
	struct spdk_nvme_ctrlr *dummy = NULL;

	/* test when probe_cb returns false */
	MOCK_SET(dummy_probe_cb, bool, false)
	rc = nvme_ctrlr_probe(trid, devhandle, dummy_probe_cb, cb_ctx);
	CU_ASSERT(rc == 1);

	/* probe_cb returns true but we can't construct a ctrl */
	MOCK_SET(dummy_probe_cb, bool, true)
	MOCK_SET_P(nvme_transport_ctrlr_construct,
		   struct spdk_nvme_ctrlr *, NULL)
	rc = nvme_ctrlr_probe(trid, devhandle, dummy_probe_cb, cb_ctx);
	CU_ASSERT(rc == -1);

	/* happy path */
	g_spdk_nvme_driver = malloc(sizeof(struct nvme_driver));
	SPDK_CU_ASSERT_FATAL(g_spdk_nvme_driver != NULL);
	MOCK_SET(dummy_probe_cb, bool, true)
	MOCK_SET_P(nvme_transport_ctrlr_construct,
		   struct spdk_nvme_ctrlr *, &ut_nvme_transport_ctrlr_construct);
	TAILQ_INIT(&g_spdk_nvme_driver->init_ctrlrs);
	rc = nvme_ctrlr_probe(trid, devhandle, dummy_probe_cb, cb_ctx);
	CU_ASSERT(rc == 0);
	dummy = TAILQ_FIRST(&g_spdk_nvme_driver->init_ctrlrs);
	CU_ASSERT(dummy == &ut_nvme_transport_ctrlr_construct);

	free(g_spdk_nvme_driver);
}

static void
test_nvme_robust_mutex_init_shared(void)
{
	pthread_mutex_t mtx;
	int rc = 0;

	ut_fake_pthread_mutexattr_init = 0;
	ut_fake_pthread_mutex_init = 0;
	/* test where both pthread calls succeed */
	MOCK_SET(pthread_mutexattr_init, int, 0)
	MOCK_SET(pthread_mutex_init, int, 0)
	rc = nvme_robust_mutex_init_shared(&mtx);
	CU_ASSERT(rc == 0);

	ut_fake_pthread_mutexattr_init = -1;
	ut_fake_pthread_mutex_init = 0;
	/* test where we can't init attr's but init mutex works */
	MOCK_SET(pthread_mutexattr_init, int, -1)
	MOCK_SET(pthread_mutex_init, int, 0)
	rc = nvme_robust_mutex_init_shared(&mtx);
	/* for FreeBSD the only possible return value is 0 */
#ifndef __FreeBSD__
@@ -174,9 +214,11 @@ test_nvme_robust_mutex_init_shared(void)
	CU_ASSERT(rc == 0);
#endif

	ut_fake_pthread_mutexattr_init = 0;
	ut_fake_pthread_mutex_init = -1;
	/* test where we can init attr's but the mutex init fails */
	MOCK_SET(pthread_mutexattr_init, int, 0)
	MOCK_SET(pthread_mutex_init, int, -1)
	rc = nvme_robust_mutex_init_shared(&mtx);
	/* for FreeBSD the only possible return value is 0 */
#ifndef __FreeBSD__
	CU_ASSERT(rc != 0);
#else
@@ -447,8 +489,12 @@ int main(int argc, char **argv)
			    test_spdk_nvme_transport_id_parse_adrfam) == NULL ||
		CU_add_test(suite, "test_trid_parse_and_compare",
			    test_trid_parse_and_compare) == NULL ||
		CU_add_test(suite, "test_trid_trtype_str", test_trid_trtype_str) == NULL ||
		CU_add_test(suite, "test_trid_adrfam_str", test_trid_adrfam_str) == NULL ||
		CU_add_test(suite, "test_trid_trtype_str",
			    test_trid_trtype_str) == NULL ||
		CU_add_test(suite, "test_trid_adrfam_str",
			    test_trid_adrfam_str) == NULL ||
		CU_add_test(suite, "test_nvme_ctrlr_probe",
			    test_nvme_ctrlr_probe) == NULL ||
		CU_add_test(suite, "test_nvme_robust_mutex_init_shared",
			    test_nvme_robust_mutex_init_shared) == NULL
	) {