build: GlusterFS Unit Test Framework
This patch will allow for developers to create unit tests for their code. Documentation has been added to the patch and is available here: doc/hacker-guide/en-US/markdown/unittest.md Also, unit tests are run when RPM is created. BUG: 1067059 Change-Id: I95cf8bb0354d4ca4ed4476a0f2385436a17d2369 Signed-off-by: Vijay Bellur <vbellur@redhat.com> Signed-off-by: Luis Pabon <lpabon@redhat.com> Reviewed-on: http://review.gluster.org/7145 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Rajesh Joseph <rjoseph@redhat.com> Reviewed-by: Justin Clift <justin@gluster.org> Tested-by: Justin Clift <justin@gluster.org>
This commit is contained in:
parent
a193f2262b
commit
c817c21403
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,6 +9,8 @@ ltmain.sh
|
||||
Makefile.in
|
||||
missing
|
||||
py-compile
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.sw?
|
||||
*~
|
||||
*.lo
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "cmockery2"]
|
||||
path = cmockery2
|
||||
url = https://github.com/lpabon/cmockery2.git
|
@ -6,7 +6,7 @@ EXTRA_DIST = autogen.sh \
|
||||
gen-headers.py run-tests.sh \
|
||||
$(shell find $(top_srcdir)/tests -type f -print)
|
||||
|
||||
SUBDIRS = argp-standalone libglusterfs rpc api xlators glusterfsd \
|
||||
SUBDIRS = argp-standalone cmockery2 libglusterfs rpc api xlators glusterfsd \
|
||||
$(FUSERMOUNT_SUBDIR) doc extras cli @SYNCDAEMON_SUBDIR@
|
||||
|
||||
pkgconfigdir = @pkgconfigdir@
|
||||
|
@ -106,8 +106,15 @@ $AUTOCONF
|
||||
echo Running ${AUTOMAKE}...
|
||||
$AUTOMAKE --add-missing --copy --foreign
|
||||
|
||||
# Update git modules
|
||||
echo "Obtaining git module cmockery2 ..."
|
||||
git submodule update --init cmockery2
|
||||
|
||||
# Run autogen in the argp-standalone sub-directory
|
||||
cd argp-standalone;./autogen.sh
|
||||
echo "Running autogen.sh in argp-standalone ..."
|
||||
( cd argp-standalone;./autogen.sh )
|
||||
echo "Running autogen.sh in cmockery2 ..."
|
||||
( cd cmockery2; ./autogen.sh )
|
||||
|
||||
# Instruct user on next steps
|
||||
echo
|
||||
|
1
cmockery2
Submodule
1
cmockery2
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 4eb53ab96fd2b227fbf68c40bcc8d915b48213b9
|
14
configure.ac
14
configure.ac
@ -630,6 +630,18 @@ AC_SUBST(HAVE_LINKAT)
|
||||
dnl check for Monotonic clock
|
||||
AC_CHECK_FUNC([clock_gettime], [has_monotonic_clock=yes], AC_CHECK_LIB([rt], [clock_gettime], , AC_MSG_WARN([System doesn't have monotonic clock using contrib])))
|
||||
|
||||
dnl Add cmockery2 for unit testing
|
||||
AC_CONFIG_SUBDIRS([cmockery2])
|
||||
UNITTEST_CFLAGS='-g -Wall -DUNIT_TESTING=1 -DDEBUG -Werror -O0 --coverage'
|
||||
UNITTEST_CPPFLAGS='-I$(top_srcdir)/cmockery2/src'
|
||||
UNITTEST_LDADD='$(top_builddir)/cmockery2/libcmockery.la'
|
||||
UNITTEST_LDFLAGS=-lgcov
|
||||
CFLAGS="$CFLAGS ${UNITTEST_CPPFLAGS}"
|
||||
AC_SUBST(UNITTEST_CFLAGS)
|
||||
AC_SUBST(UNITTEST_CPPFLAGS)
|
||||
AC_SUBST(UNITTEST_LDADD)
|
||||
AC_SUBST(UNITTEST_LDFLAGS)
|
||||
|
||||
dnl Check for argp
|
||||
AC_CHECK_HEADER([argp.h], AC_DEFINE(HAVE_ARGP, 1, [have argp]))
|
||||
AC_CONFIG_SUBDIRS(argp-standalone)
|
||||
@ -900,7 +912,7 @@ CONTRIBDIR='$(top_srcdir)/contrib'
|
||||
AC_SUBST(CONTRIBDIR)
|
||||
|
||||
GF_CPPDEFINES='-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)'
|
||||
GF_CPPINCLUDES='-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/uuid'
|
||||
GF_CPPINCLUDES='-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/uuid $(UNITTEST_CPPFLAGS)'
|
||||
GF_CPPFLAGS="$GF_CPPDEFINES $GF_CPPINCLUDES"
|
||||
AC_SUBST([GF_CPPFLAGS])
|
||||
|
||||
|
227
doc/hacker-guide/en-US/markdown/unittest.md
Normal file
227
doc/hacker-guide/en-US/markdown/unittest.md
Normal file
@ -0,0 +1,227 @@
|
||||
# Unit Tests in GlusterFS
|
||||
|
||||
## Overview
|
||||
[Art-of-unittesting][definitionofunittest] provides a good definition for unit tests. A good unit test is:
|
||||
|
||||
* Able to be fully automated
|
||||
* Has full control over all the pieces running (Use mocks or stubs to achieve this isolation when needed)
|
||||
* Can be run in any order if part of many other tests
|
||||
* Runs in memory (no DB or File access, for example)
|
||||
* Consistently returns the same result (You always run the same test, so no random numbers, for example. save those for integration or range tests)
|
||||
* Runs fast
|
||||
* Tests a single logical concept in the system
|
||||
* Readable
|
||||
* Maintainable
|
||||
* Trustworthy (when you see its result, you don’t need to debug the code just to be sure)
|
||||
|
||||
## Cmockery2
|
||||
GlusterFS unit test framework is based on [Cmockery2][]. Cmockery provides developers with methods to isolate and test modules written in C language. It also provides integration with Jenkins by providing JUnit XML compliant unit test results.
|
||||
|
||||
Before continuing, you may want to familiarize yourself with Cmockery2 by reading the [usage guide][cmockery2usage].
|
||||
|
||||
## Running Unit Tests
|
||||
To execute the unit tests, all you need is to type `make check`. Here is a step-by-step example assuming you just cloned a GlusterFS tree:
|
||||
|
||||
```
|
||||
$ ./autogen.sh
|
||||
$ ./configure --enable-debug
|
||||
$ make check
|
||||
```
|
||||
|
||||
Sample output:
|
||||
|
||||
```
|
||||
PASS: mem_pool_unittest
|
||||
============================================================================
|
||||
Testsuite summary for glusterfs 3git
|
||||
============================================================================
|
||||
# TOTAL: 1
|
||||
# PASS: 1
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
```
|
||||
|
||||
In this example, `mem_pool_unittest` has multiple tests inside, but `make check` assumes that the program itself is the test, and that is why it only shows one test. Here is the output when we run `mem_pool_unittest` directly:
|
||||
|
||||
```
|
||||
$ ./libglusterfs/src/mem_pool_unittest
|
||||
[==========] Running 10 test(s).
|
||||
[ RUN ] test_gf_mem_acct_enable_set
|
||||
Expected assertion data != ((void *)0) occurred
|
||||
[ OK ] test_gf_mem_acct_enable_set
|
||||
[ RUN ] test_gf_mem_set_acct_info_asserts
|
||||
Expected assertion xl != ((void *)0) occurred
|
||||
Expected assertion size > ((4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8) + 8) occurred
|
||||
Expected assertion type <= xl->mem_acct.num_types occurred
|
||||
[ OK ] test_gf_mem_set_acct_info_asserts
|
||||
[ RUN ] test_gf_mem_set_acct_info_memory
|
||||
[ OK ] test_gf_mem_set_acct_info_memory
|
||||
[ RUN ] test_gf_calloc_default_calloc
|
||||
[ OK ] test_gf_calloc_default_calloc
|
||||
[ RUN ] test_gf_calloc_mem_acct_enabled
|
||||
[ OK ] test_gf_calloc_mem_acct_enabled
|
||||
[ RUN ] test_gf_malloc_default_malloc
|
||||
[ OK ] test_gf_malloc_default_malloc
|
||||
[ RUN ] test_gf_malloc_mem_acct_enabled
|
||||
[ OK ] test_gf_malloc_mem_acct_enabled
|
||||
[ RUN ] test_gf_realloc_default_realloc
|
||||
[ OK ] test_gf_realloc_default_realloc
|
||||
[ RUN ] test_gf_realloc_mem_acct_enabled
|
||||
[ OK ] test_gf_realloc_mem_acct_enabled
|
||||
[ RUN ] test_gf_realloc_ptr
|
||||
Expected assertion ((void *)0) != ptr occurred
|
||||
[ OK ] test_gf_realloc_ptr
|
||||
[==========] 10 test(s) run.
|
||||
[ PASSED ] 10 test(s).
|
||||
[ FAILED ] 0 test(s).
|
||||
[ REPORT ] Created libglusterfs_mem_pool_xunit.xml report
|
||||
```
|
||||
|
||||
|
||||
## Writing Unit Tests
|
||||
|
||||
### Enhancing your C functions
|
||||
|
||||
#### Programming by Contract
|
||||
Add the following to your C file:
|
||||
|
||||
```c
|
||||
#include <cmockery/pbc.h>
|
||||
```
|
||||
|
||||
```c
|
||||
/*
|
||||
* Programming by Contract is a programming methodology
|
||||
* which binds the caller and the function called to a
|
||||
* contract. The contract is represented using Hoare Triple:
|
||||
* {P} C {Q}
|
||||
* where {P} is the precondition before executing command C,
|
||||
* and {Q} is the postcondition.
|
||||
*
|
||||
* See also:
|
||||
* http://en.wikipedia.org/wiki/Design_by_contract
|
||||
* http://en.wikipedia.org/wiki/Hoare_logic
|
||||
* http://dlang.org/dbc.html
|
||||
*/
|
||||
#ifndef CMOCKERY_PBC_H_
|
||||
#define CMOCKERY_PBC_H_
|
||||
|
||||
#if defined(UNIT_TESTING) || defined (DEBUG)
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Checks caller responsability against contract
|
||||
*/
|
||||
#define REQUIRE(cond) assert(cond)
|
||||
|
||||
/*
|
||||
* Checks function reponsability against contract.
|
||||
*/
|
||||
#define ENSURE(cond) assert(cond)
|
||||
|
||||
/*
|
||||
* While REQUIRE and ENSURE apply to functions, INVARIANT
|
||||
* applies to classes/structs. It ensures that intances
|
||||
* of the class/struct are consistant. In other words,
|
||||
* that the instance has not been corrupted.
|
||||
*/
|
||||
#define INVARIANT(invariant_fnc) do{ (invariant_fnc) } while (0);
|
||||
|
||||
#else
|
||||
#define REQUIRE(cond) do { } while (0);
|
||||
#define ENSURE(cond) do { } while (0);
|
||||
#define INVARIANT(invariant_fnc) do{ } while (0);
|
||||
|
||||
#endif /* defined(UNIT_TESTING) || defined (DEBUG) */
|
||||
#endif /* CMOCKERY_PBC_H_ */
|
||||
```
|
||||
|
||||
##### Example
|
||||
This is an _extremely_ simple example:
|
||||
|
||||
```c
|
||||
int divide (int n, int d)
|
||||
{
|
||||
int ans;
|
||||
|
||||
REQUIRE(d != 0);
|
||||
|
||||
ans = n / d;
|
||||
|
||||
// As code is added to this function throughout its lifetime,
|
||||
// ENSURE will assert that data will be returned
|
||||
// according to the contract. Again this is an
|
||||
// extremely simple example. :-D
|
||||
ENSURE( ans == (n / d) );
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
##### Important Note
|
||||
`REQUIRE`, `ENSURE`, and `INVARIANT` are only available when `DEBUG` or `UNIT_TESTING` are set in the CFLAGS. You must pass `--enable-debug` to `./configure` to enable PBC on your non-unittest builds.
|
||||
|
||||
#### Overriding functions
|
||||
Cmockery2 provides its own memory allocation functions which check for buffer overrun and memory leaks. The following header file must be included **last** to be able to override any of the memory allocation functions:
|
||||
|
||||
```c
|
||||
#include <cmockery/cmockery_override.h>
|
||||
```
|
||||
|
||||
This file will only take effect with the `UNIT_TESTING` CFLAG is set.
|
||||
|
||||
### Creating a unit test
|
||||
Once you identify the C file you would like to test, first create a `unittest` directory under the directory where the C file is located. This will isolate the unittests to a different directory.
|
||||
|
||||
Next, you need to edit the `Makefile.am` file in the directory where your C file is located. Initialize the
|
||||
`Makefile.am` if it does not already have the following sections:
|
||||
|
||||
```
|
||||
#### UNIT TESTS #####
|
||||
CLEANFILES += *.gcda *.gcno *_xunit.xml
|
||||
noinst_PROGRAMS =
|
||||
TESTS =
|
||||
```
|
||||
|
||||
Now you can add the following for each of the unit tests that you would like to build:
|
||||
|
||||
```
|
||||
### UNIT TEST xxx_unittest ###
|
||||
xxx_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(xxx_CPPFLAGS)
|
||||
xxx_unittest_SOURCES = xxx.c \
|
||||
unittest/xxx_unittest.c
|
||||
xxx_unittest_CFLAGS = $(UNITTEST_CFLAGS)
|
||||
xxx_unittest_LDADD = $(UNITTEST_LDADD)
|
||||
xxx_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
|
||||
noinst_PROGRAMS += xxx_unittest
|
||||
TESTS += xxx_unittest
|
||||
```
|
||||
|
||||
Where `xxx` is the name of your C file. For example, look at `libglusterfs/src/Makefile.am`.
|
||||
|
||||
Copy the simple unit test from `cmockery2/src/example/run_tests.c` to `unittest/xxx_unittest.c`. If you would like to see an example of a unit test, please refer to `libglusterfs/src/unittest/mem_pool_unittest.c`.
|
||||
|
||||
#### Mocking
|
||||
You may see that the linker will complain about missing functions needed by the C file you would like to test. Identify the required functions, then place their stubs in a file called `unittest/xxx_mock.c`, then include this file in `Makefile.am` in `xxx_unittest_SOURCES`. This will allow you to you Cmockery2's mocking functions.
|
||||
|
||||
#### Running the unit test
|
||||
You can type `make` in the directory where the C file is located. Once you built it and there are no errors, you can execute the test either by directly executing the program (in our example above it is called `xxx_unittest` ), or by running `make check`.
|
||||
|
||||
#### Debugging
|
||||
Sometimes you may need to debug your unit test. To do that, you will have to point `gdb` to the actual binary which is located in the `.libs` subdirectory. For example, you can do the following from the root of the source tree to debug `mem_pool_unittest`:
|
||||
|
||||
```
|
||||
$ export LD_LIBRARY_PATH=cmockery2/.libs
|
||||
$ gdb ./libglusterfs/src/.libs/mem_pool_unittest
|
||||
```
|
||||
|
||||
|
||||
[Cmockery2]: https://github.com/lpabon/cmockery2
|
||||
[definitionofunittest]: http://artofunittesting.com/definition-of-a-unit-test/
|
||||
[cmockery2usage]: https://github.com/lpabon/cmockery2/blob/master/doc/usage.md
|
@ -450,6 +450,10 @@ pushd api/examples
|
||||
FLAGS="$RPM_OPT_FLAGS" python setup.py build
|
||||
popd
|
||||
|
||||
%check
|
||||
|
||||
LD_LIBRARY_PATH=$PWD/cmockery2/.libs make check
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
make install DESTDIR=%{buildroot}
|
||||
@ -666,6 +670,9 @@ rm -rf %{buildroot}
|
||||
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/encryption/rot-13*
|
||||
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/mac-compat*
|
||||
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/testing/performance/symlink-cache*
|
||||
# exclude cmockery
|
||||
%exclude %{_includedir}/cmockery*
|
||||
%exclude %{_prefix}/share/doc/cmockery*
|
||||
|
||||
%post libs
|
||||
/sbin/ldconfig
|
||||
|
@ -55,3 +55,20 @@ y.tab.h: graph.y
|
||||
|
||||
CLEANFILES = graph.lex.c y.tab.c y.tab.h
|
||||
CONFIG_CLEAN_FILES = $(CONTRIB_BUILDDIR)/uuid/uuid_types.h
|
||||
|
||||
#### UNIT TESTS #####
|
||||
CLEANFILES += *.gcda *.gcno *_xunit.xml
|
||||
noinst_PROGRAMS =
|
||||
TESTS =
|
||||
|
||||
mem_pool_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(libglusterfs_la_CPPFLAGS)
|
||||
mem_pool_unittest_SOURCES = mem-pool.c \
|
||||
mem-pool.h \
|
||||
unittest/mem_pool_unittest.c \
|
||||
unittest/log_mock.c \
|
||||
unittest/global_mock.c
|
||||
mem_pool_unittest_CFLAGS = $(UNITTEST_CFLAGS)
|
||||
mem_pool_unittest_LDADD = $(UNITTEST_LDADD)
|
||||
mem_pool_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
|
||||
noinst_PROGRAMS += mem_pool_unittest
|
||||
TESTS += mem_pool_unittest
|
||||
|
@ -22,29 +22,30 @@
|
||||
#define is_mem_chunk_in_use(ptr) (*ptr == 1)
|
||||
#define mem_pool_from_ptr(ptr) ((ptr) + GF_MEM_POOL_LIST_BOUNDARY)
|
||||
|
||||
#define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8)
|
||||
#define GF_MEM_TRAILER_SIZE 8
|
||||
|
||||
#define GF_MEM_HEADER_MAGIC 0xCAFEBABE
|
||||
#define GF_MEM_TRAILER_MAGIC 0xBAADF00D
|
||||
|
||||
#define GLUSTERFS_ENV_MEM_ACCT_STR "GLUSTERFS_DISABLE_MEM_ACCT"
|
||||
|
||||
#include <cmockery/pbc.h>
|
||||
#include <cmockery/cmockery_override.h>
|
||||
|
||||
void
|
||||
gf_mem_acct_enable_set (void *data)
|
||||
{
|
||||
glusterfs_ctx_t *ctx = NULL;
|
||||
|
||||
REQUIRE(data != NULL);
|
||||
|
||||
ctx = data;
|
||||
|
||||
GF_ASSERT (ctx);
|
||||
GF_ASSERT (ctx != NULL);
|
||||
|
||||
ctx->mem_acct_enable = 1;
|
||||
|
||||
ENSURE(1 == ctx->mem_acct_enable);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
|
||||
size_t size, uint32_t type)
|
||||
{
|
||||
@ -52,7 +53,7 @@ gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
|
||||
char *ptr = NULL;
|
||||
|
||||
if (!alloc_ptr)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
ptr = (char *) (*alloc_ptr);
|
||||
|
||||
@ -88,7 +89,7 @@ gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
|
||||
*(uint32_t *) (ptr + size) = GF_MEM_TRAILER_MAGIC;
|
||||
|
||||
*alloc_ptr = (void *)ptr;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -150,10 +151,13 @@ __gf_realloc (void *ptr, size_t size)
|
||||
char *orig_ptr = NULL;
|
||||
xlator_t *xl = NULL;
|
||||
uint32_t type = 0;
|
||||
char *new_ptr;
|
||||
|
||||
if (!THIS->ctx->mem_acct_enable)
|
||||
return REALLOC (ptr, size);
|
||||
|
||||
REQUIRE(NULL != ptr);
|
||||
|
||||
tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE;
|
||||
|
||||
orig_ptr = (char *)ptr - 8 - 4;
|
||||
@ -166,15 +170,22 @@ __gf_realloc (void *ptr, size_t size)
|
||||
orig_ptr = (char *)ptr - GF_MEM_HEADER_SIZE;
|
||||
type = *(uint32_t *)orig_ptr;
|
||||
|
||||
ptr = realloc (orig_ptr, tot_size);
|
||||
if (!ptr) {
|
||||
new_ptr = realloc (orig_ptr, tot_size);
|
||||
if (!new_ptr) {
|
||||
gf_log_nomem ("", GF_LOG_ALERT, tot_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gf_mem_set_acct_info (xl, (char **)&ptr, size, type);
|
||||
/*
|
||||
* We used to pass (char **)&ptr as the second
|
||||
* argument after the value of realloc was saved
|
||||
* in ptr, but the compiler warnings complained
|
||||
* about the casting to and forth from void ** to
|
||||
* char **.
|
||||
*/
|
||||
gf_mem_set_acct_info (xl, &new_ptr, size, type);
|
||||
|
||||
return (void *)ptr;
|
||||
return (void *)new_ptr;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -20,6 +20,19 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* Need this for unit tests since inline functions
|
||||
* access memory allocation and need to use the
|
||||
* unit test versions
|
||||
*/
|
||||
#ifdef UNIT_TESTING
|
||||
#include <cmockery/cmockery_override.h>
|
||||
#endif
|
||||
|
||||
#define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8)
|
||||
#define GF_MEM_TRAILER_SIZE 8
|
||||
#define GF_MEM_HEADER_MAGIC 0xCAFEBABE
|
||||
#define GF_MEM_TRAILER_MAGIC 0xBAADF00D
|
||||
|
||||
struct mem_acct {
|
||||
uint32_t num_types;
|
||||
|
24
libglusterfs/src/unittest/global_mock.c
Normal file
24
libglusterfs/src/unittest/global_mock.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
This file is licensed to you under your choice of the GNU Lesser
|
||||
General Public License, version 3 or any later version (LGPLv3 or
|
||||
later), or the GNU General Public License, version 2 (GPLv2), in all
|
||||
cases as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "logging.h"
|
||||
#include "xlator.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <cmockery/cmockery.h>
|
||||
|
||||
xlator_t **__glusterfs_this_location ()
|
||||
{
|
||||
return ((xlator_t **)(uintptr_t)mock());
|
||||
}
|
43
libglusterfs/src/unittest/log_mock.c
Normal file
43
libglusterfs/src/unittest/log_mock.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
This file is licensed to you under your choice of the GNU Lesser
|
||||
General Public License, version 3 or any later version (LGPLv3 or
|
||||
later), or the GNU General Public License, version 2 (GPLv2), in all
|
||||
cases as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "logging.h"
|
||||
#include "xlator.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <cmockery/cmockery.h>
|
||||
|
||||
int _gf_log (const char *domain, const char *file,
|
||||
const char *function, int32_t line, gf_loglevel_t level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gf_log_callingfn (const char *domain, const char *file,
|
||||
const char *function, int32_t line, gf_loglevel_t level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gf_log_nomem (const char *domain, const char *file,
|
||||
const char *function, int line, gf_loglevel_t level,
|
||||
size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gf_log_globals_init (void *data) {}
|
472
libglusterfs/src/unittest/mem_pool_unittest.c
Normal file
472
libglusterfs/src/unittest/mem_pool_unittest.c
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
This file is licensed to you under your choice of the GNU Lesser
|
||||
General Public License, version 3 or any later version (LGPLv3 or
|
||||
later), or the GNU General Public License, version 2 (GPLv2), in all
|
||||
cases as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "mem-pool.h"
|
||||
#include "logging.h"
|
||||
#include "xlator.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <cmockery/pbc.h>
|
||||
#include <cmockery/cmockery.h>
|
||||
|
||||
/*
|
||||
* memory header for gf_mem_set_acct_info
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t type;
|
||||
size_t size;
|
||||
xlator_t *xl;
|
||||
uint32_t header_magic;
|
||||
uint8_t pad[8];
|
||||
} mem_header_t;
|
||||
|
||||
/*
|
||||
* Prototypes to private functions
|
||||
*/
|
||||
int
|
||||
gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
|
||||
size_t size, uint32_t type);
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
*/
|
||||
static xlator_t *
|
||||
helper_xlator_init(uint32_t num_types)
|
||||
{
|
||||
xlator_t *xl;
|
||||
int i, ret;
|
||||
|
||||
REQUIRE(num_types > 0);
|
||||
|
||||
xl = test_calloc(1, sizeof(xlator_t));
|
||||
assert_non_null(xl);
|
||||
xl->mem_acct.num_types = num_types;
|
||||
xl->mem_acct.rec = test_calloc(num_types, sizeof(struct mem_acct_rec));
|
||||
assert_non_null(xl->mem_acct.rec);
|
||||
|
||||
xl->ctx = test_calloc(1, sizeof(glusterfs_ctx_t));
|
||||
assert_non_null(xl->ctx);
|
||||
|
||||
for (i = 0; i < num_types; i++) {
|
||||
ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock));
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
ENSURE(num_types == xl->mem_acct.num_types);
|
||||
ENSURE(NULL != xl);
|
||||
|
||||
return xl;
|
||||
}
|
||||
|
||||
static int
|
||||
helper_xlator_destroy(xlator_t *xl)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < xl->mem_acct.num_types; i++) {
|
||||
ret = LOCK_DESTROY(&(xl->mem_acct.rec[i].lock));
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
free(xl->mem_acct.rec);
|
||||
free(xl->ctx);
|
||||
free(xl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
helper_check_memory_headers( char *mem,
|
||||
xlator_t *xl,
|
||||
size_t size,
|
||||
uint32_t type)
|
||||
{
|
||||
mem_header_t *p;
|
||||
|
||||
p = (mem_header_t *)mem,
|
||||
assert_int_equal(p->type, type);
|
||||
assert_int_equal(p->size, size);
|
||||
assert_true(p->xl == xl);
|
||||
assert_int_equal(p->header_magic, GF_MEM_HEADER_MAGIC);
|
||||
assert_true(*(uint32_t *)(mem+sizeof(mem_header_t)+size) == GF_MEM_TRAILER_MAGIC);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests
|
||||
*/
|
||||
static void
|
||||
test_gf_mem_acct_enable_set(void **state)
|
||||
{
|
||||
(void) state;
|
||||
glusterfs_ctx_t test_ctx;
|
||||
|
||||
expect_assert_failure(gf_mem_acct_enable_set(NULL));
|
||||
|
||||
memset(&test_ctx, 0, sizeof(test_ctx));
|
||||
assert_true(NULL == test_ctx.process_uuid);
|
||||
gf_mem_acct_enable_set((void *)&test_ctx);
|
||||
assert_true(1 == test_ctx.mem_acct_enable);
|
||||
assert_true(NULL == test_ctx.process_uuid);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_mem_set_acct_info_asserts(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
xlator_t xltest;
|
||||
char *alloc_ptr;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
memset(&xltest, 0, sizeof(xlator_t));
|
||||
xl = (xlator_t *)0xBADD;
|
||||
alloc_ptr = (char *)0xBADD;
|
||||
size = 8196;
|
||||
type = 0;
|
||||
|
||||
|
||||
// Check xl is NULL
|
||||
expect_assert_failure(gf_mem_set_acct_info(NULL, &alloc_ptr, size, type));
|
||||
// Check xl->mem_acct.rec = NULL
|
||||
expect_assert_failure(gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type));
|
||||
// Check type <= xl->mem_acct.num_types
|
||||
type = 100;
|
||||
expect_assert_failure(gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type));
|
||||
// Check alloc is NULL
|
||||
assert_int_equal(-1, gf_mem_set_acct_info(&xltest, NULL, size, type));
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
|
||||
// Test number of types
|
||||
type = 100;
|
||||
assert_true(NULL != xl->mem_acct.rec);
|
||||
assert_true(type > xl->mem_acct.num_types);
|
||||
expect_assert_failure(gf_mem_set_acct_info(xl, &alloc_ptr, size, type));
|
||||
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_mem_set_acct_info_memory(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
char *alloc_ptr;
|
||||
char *temp_ptr;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
size = 8196;
|
||||
type = 9;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
|
||||
// Test allocation
|
||||
temp_ptr = test_calloc(1, size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE);
|
||||
assert_non_null(temp_ptr);
|
||||
alloc_ptr = temp_ptr;
|
||||
gf_mem_set_acct_info(xl, &alloc_ptr, size, type);
|
||||
|
||||
//Check values
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
|
||||
|
||||
// Check memory
|
||||
helper_check_memory_headers(temp_ptr, xl, size, type);
|
||||
|
||||
// Check that alloc_ptr has been moved correctly
|
||||
// by gf_mem_set_acct_info
|
||||
{
|
||||
mem_header_t *p;
|
||||
|
||||
p = (mem_header_t *)temp_ptr;
|
||||
p++;
|
||||
p->type = 1234;
|
||||
assert_int_equal(*(uint32_t *)alloc_ptr, p->type);
|
||||
}
|
||||
|
||||
free(temp_ptr);
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_calloc_default_calloc(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
will_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_calloc
|
||||
size = 1024;
|
||||
type = 3;
|
||||
mem = __gf_calloc(1, size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl did not change
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
|
||||
|
||||
free(mem);
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_calloc_mem_acct_enabled(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
xl->ctx->mem_acct_enable = 1;
|
||||
|
||||
// For line mem-pool.c:115 and mem-pool:118
|
||||
will_always_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_calloc
|
||||
size = 1024;
|
||||
type = 3;
|
||||
mem = __gf_calloc(1, size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl values
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
|
||||
|
||||
// Check memory
|
||||
helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
|
||||
free(mem - sizeof(mem_header_t));
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_malloc_default_malloc(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
will_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_malloc
|
||||
size = 1024;
|
||||
type = 3;
|
||||
mem = __gf_malloc(size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl did not change
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
|
||||
|
||||
free(mem);
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_malloc_mem_acct_enabled(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
xl->ctx->mem_acct_enable = 1;
|
||||
|
||||
// For line mem-pool.c:115 and mem-pool:118
|
||||
will_always_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_malloc
|
||||
size = 1024;
|
||||
type = 3;
|
||||
mem = __gf_malloc(size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl values
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, size);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
|
||||
|
||||
// Check memory
|
||||
helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
|
||||
free(mem - sizeof(mem_header_t));
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_realloc_default_realloc(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
will_always_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_malloc then realloc
|
||||
size = 10;
|
||||
type = 3;
|
||||
mem = __gf_malloc(size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0xA5, size);
|
||||
|
||||
size = 1024;
|
||||
mem = __gf_realloc(mem, size);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl did not change
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
|
||||
|
||||
free(mem);
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_realloc_mem_acct_enabled(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
xl->ctx->mem_acct_enable = 1;
|
||||
|
||||
// For line mem-pool.c:115 and mem-pool:118
|
||||
will_always_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Call __gf_malloc then realloc
|
||||
size = 1024;
|
||||
type = 3;
|
||||
mem = __gf_malloc(size, type);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0xA5, size);
|
||||
|
||||
size = 2048;
|
||||
mem = __gf_realloc(mem, size);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0x5A, size);
|
||||
|
||||
// Check xl values
|
||||
//
|
||||
// :TODO: This is really weird. I would have expected
|
||||
// xl to only have a size equal to that of the realloc
|
||||
// not to the realloc + the malloc.
|
||||
// Is this a bug?
|
||||
//
|
||||
assert_int_equal(xl->mem_acct.rec[type].size, size+1024);
|
||||
assert_int_equal(xl->mem_acct.rec[type].num_allocs, 2);
|
||||
assert_int_equal(xl->mem_acct.rec[type].total_allocs, 2);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_size, size+1024);
|
||||
assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 2);
|
||||
|
||||
// Check memory
|
||||
helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
|
||||
free(mem - sizeof(mem_header_t));
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_gf_realloc_ptr(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
void *mem;
|
||||
size_t size;
|
||||
|
||||
// Initialize xl
|
||||
xl = helper_xlator_init(10);
|
||||
assert_int_equal(xl->ctx->mem_acct_enable, 0);
|
||||
|
||||
// For line mem-pool.c:115 and mem-pool:118
|
||||
will_always_return(__glusterfs_this_location, &xl);
|
||||
|
||||
// Tests according to the manpage for realloc
|
||||
|
||||
// Like a malloc
|
||||
size = 1024;
|
||||
mem = __gf_realloc(NULL, size);
|
||||
assert_non_null(mem);
|
||||
memset(mem, 0xA5, size);
|
||||
|
||||
// Like a free
|
||||
mem = __gf_realloc(mem, 0);
|
||||
assert_null(mem);
|
||||
|
||||
// Now enable xl context
|
||||
xl->ctx->mem_acct_enable = 1;
|
||||
expect_assert_failure(__gf_realloc(NULL, size));
|
||||
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
const UnitTest tests[] = {
|
||||
unit_test(test_gf_mem_acct_enable_set),
|
||||
unit_test(test_gf_mem_set_acct_info_asserts),
|
||||
unit_test(test_gf_mem_set_acct_info_memory),
|
||||
unit_test(test_gf_calloc_default_calloc),
|
||||
unit_test(test_gf_calloc_mem_acct_enabled),
|
||||
unit_test(test_gf_malloc_default_malloc),
|
||||
unit_test(test_gf_malloc_mem_acct_enabled),
|
||||
unit_test(test_gf_realloc_default_realloc),
|
||||
unit_test(test_gf_realloc_mem_acct_enabled),
|
||||
unit_test(test_gf_realloc_ptr),
|
||||
};
|
||||
|
||||
return run_tests(tests, "libglusterfs_mem_pool");
|
||||
}
|
@ -36,3 +36,18 @@ uninstall-local:
|
||||
|
||||
install-data-hook:
|
||||
ln -sf dht.so $(DESTDIR)$(xlatordir)/distribute.so
|
||||
|
||||
#### UNIT TESTS #####
|
||||
CLEANFILES += *.gcda *.gcno *_xunit.xml
|
||||
noinst_PROGRAMS =
|
||||
TESTS =
|
||||
|
||||
dht_layout_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(AM_CPPFLAGS)
|
||||
dht_layout_unittest_SOURCES = unittest/dht_layout_unittest.c \
|
||||
unittest/dht_layout_mock.c \
|
||||
dht-layout.c
|
||||
dht_layout_unittest_CFLAGS = $(UNITTEST_CFLAGS)
|
||||
dht_layout_unittest_LDADD = $(UNITTEST_LDADD)
|
||||
dht_layout_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
|
||||
noinst_PROGRAMS += dht_layout_unittest
|
||||
TESTS += dht_layout_unittest
|
||||
|
@ -25,6 +25,19 @@
|
||||
|
||||
#define layout_size(cnt) (layout_base_size + (cnt * layout_entry_size))
|
||||
|
||||
#include <cmockery/pbc.h>
|
||||
#include <cmockery/cmockery_override.h>
|
||||
|
||||
// Change GF_CALLOC and GF_FREE to use
|
||||
// cmockery2 memory allocation versions
|
||||
#ifdef UNIT_TESTING
|
||||
#undef GF_CALLOC
|
||||
#define GF_CALLOC(n, s, t) test_calloc(n, s)
|
||||
#undef GF_FREE
|
||||
#define GF_FREE test_free
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
dht_layout_t *
|
||||
dht_layout_new (xlator_t *this, int cnt)
|
||||
@ -32,6 +45,8 @@ dht_layout_new (xlator_t *this, int cnt)
|
||||
dht_layout_t *layout = NULL;
|
||||
dht_conf_t *conf = NULL;
|
||||
|
||||
REQUIRE(NULL != this);
|
||||
REQUIRE(cnt >= 0);
|
||||
|
||||
conf = this->private;
|
||||
|
||||
@ -50,6 +65,11 @@ dht_layout_new (xlator_t *this, int cnt)
|
||||
}
|
||||
|
||||
layout->ref = 1;
|
||||
|
||||
ENSURE(NULL != layout);
|
||||
ENSURE(layout->type == DHT_HASH_TYPE_DM);
|
||||
ENSURE(layout->cnt == cnt);
|
||||
ENSURE(layout->ref == 1);
|
||||
out:
|
||||
return layout;
|
||||
}
|
||||
|
63
xlators/cluster/dht/src/unittest/dht_layout_mock.c
Normal file
63
xlators/cluster/dht/src/unittest/dht_layout_mock.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
This file is licensed to you under your choice of the GNU Lesser
|
||||
General Public License, version 3 or any later version (LGPLv3 or
|
||||
later), or the GNU General Public License, version 2 (GPLv2), in all
|
||||
cases as published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "glusterfs.h"
|
||||
#include "xlator.h"
|
||||
#include "dht-common.h"
|
||||
#include "byte-order.h"
|
||||
|
||||
int
|
||||
dht_hash_compute (xlator_t *this, int type, const char *name, uint32_t *hash_p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dht_inode_ctx_layout_get (inode_t *inode, xlator_t *this, dht_layout_t **layout)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dht_inode_ctx_layout_set (inode_t *inode, xlator_t *this,
|
||||
dht_layout_t *layout_int)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dict_get_ptr (dict_t *this, char *key, void **ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dict_get_ptr_and_len (dict_t *this, char *key, void **ptr, int *len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gf_log (const char *domain, const char *file,
|
||||
const char *function, int32_t line, gf_loglevel_t level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gf_log_callingfn (const char *domain, const char *file,
|
||||
const char *function, int32_t line, gf_loglevel_t level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
124
xlators/cluster/dht/src/unittest/dht_layout_unittest.c
Normal file
124
xlators/cluster/dht/src/unittest/dht_layout_unittest.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014 Red Hat, Inc. <http://www.redhat.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
This file is licensed to you under your choice of the GNU Lesser
|
||||
General Public License, version 3 or any later version (LGPLv3 or
|
||||
later), or the GNU General Public License, version 2 (GPLv2), in all
|
||||
cases as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "dht-common.h"
|
||||
#include "logging.h"
|
||||
#include "xlator.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
#include <cmockery/pbc.h>
|
||||
#include <cmockery/cmockery.h>
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
static xlator_t *
|
||||
helper_xlator_init(uint32_t num_types)
|
||||
{
|
||||
xlator_t *xl;
|
||||
int i, ret;
|
||||
|
||||
REQUIRE(num_types > 0);
|
||||
|
||||
xl = test_calloc(1, sizeof(xlator_t));
|
||||
assert_non_null(xl);
|
||||
xl->mem_acct.num_types = num_types;
|
||||
xl->mem_acct.rec = test_calloc(num_types, sizeof(struct mem_acct_rec));
|
||||
assert_non_null(xl->mem_acct.rec);
|
||||
|
||||
xl->ctx = test_calloc(1, sizeof(glusterfs_ctx_t));
|
||||
assert_non_null(xl->ctx);
|
||||
|
||||
for (i = 0; i < num_types; i++) {
|
||||
ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock));
|
||||
assert_false(ret);
|
||||
}
|
||||
|
||||
ENSURE(num_types == xl->mem_acct.num_types);
|
||||
ENSURE(NULL != xl);
|
||||
|
||||
return xl;
|
||||
}
|
||||
|
||||
static int
|
||||
helper_xlator_destroy(xlator_t *xl)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < xl->mem_acct.num_types; i++) {
|
||||
ret = LOCK_DESTROY(&(xl->mem_acct.rec[i].lock));
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
free(xl->mem_acct.rec);
|
||||
free(xl->ctx);
|
||||
free(xl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unit tests
|
||||
*/
|
||||
static void
|
||||
test_dht_layout_new(void **state)
|
||||
{
|
||||
xlator_t *xl;
|
||||
dht_layout_t *layout;
|
||||
dht_conf_t *conf;
|
||||
int cnt;
|
||||
|
||||
expect_assert_failure(dht_layout_new(NULL, 0));
|
||||
expect_assert_failure(dht_layout_new((xlator_t *)0x12345, -1));
|
||||
xl = helper_xlator_init(10);
|
||||
|
||||
// xl->private is NULL
|
||||
assert_null(xl->private);
|
||||
cnt = 100;
|
||||
layout = dht_layout_new(xl, cnt);
|
||||
assert_non_null(layout);
|
||||
assert_int_equal(layout->type, DHT_HASH_TYPE_DM);
|
||||
assert_int_equal(layout->cnt, cnt);
|
||||
assert_int_equal(layout->ref, 1);
|
||||
assert_int_equal(layout->gen, 0);
|
||||
assert_int_equal(layout->spread_cnt, 0);
|
||||
free(layout);
|
||||
|
||||
// xl->private is not NULL
|
||||
cnt = 110;
|
||||
conf = (dht_conf_t *)test_calloc(1, sizeof(dht_conf_t));
|
||||
assert_non_null(conf);
|
||||
conf->dir_spread_cnt = 12345;
|
||||
conf->gen = -123;
|
||||
xl->private = conf;
|
||||
|
||||
layout = dht_layout_new(xl, cnt);
|
||||
assert_non_null(layout);
|
||||
assert_int_equal(layout->type, DHT_HASH_TYPE_DM);
|
||||
assert_int_equal(layout->cnt, cnt);
|
||||
assert_int_equal(layout->ref, 1);
|
||||
assert_int_equal(layout->gen, conf->gen);
|
||||
assert_int_equal(layout->spread_cnt, conf->dir_spread_cnt);
|
||||
free(layout);
|
||||
|
||||
free(conf);
|
||||
helper_xlator_destroy(xl);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
const UnitTest tests[] = {
|
||||
unit_test(test_dht_layout_new),
|
||||
};
|
||||
|
||||
return run_tests(tests, "xlator_dht_layout");
|
||||
}
|
@ -266,6 +266,16 @@ _posix_xattr_get_set (dict_t *xattr_req,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* There could be a situation where the ia_size is
|
||||
* zero. GF_CALLOC will return a pointer to the
|
||||
* memory initialized by gf_mem_set_acct_info.
|
||||
* This function adds a header and a footer to
|
||||
* the allocated memory. The returned pointer
|
||||
* points to the memory just after the header, but
|
||||
* when size is zero, there is no space for user
|
||||
* data. The memory can be freed by calling GF_FREE.
|
||||
*/
|
||||
databuf = GF_CALLOC (1, filler->stbuf->ia_size,
|
||||
gf_posix_mt_char);
|
||||
if (!databuf) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user