1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-09-08 04:26:59 +03:00

[unit-test] Push the new unit test framwork.

See doc/unit-test.txt for details.

Some bcache tests failing.  Probably due to dct changing semantics, will
fix in follow up patch.
This commit is contained in:
Joe Thornber 2018-04-26 11:59:39 +01:00
parent c7fdacbc50
commit ea34dad66f
47 changed files with 1544 additions and 1591 deletions

2
.gitignore vendored
View File

@ -79,3 +79,5 @@ test/lib/vgrename
test/lib/vgs
test/lib/vgscan
test/lib/vgsplit
unit-test/unit-test

View File

@ -43,8 +43,7 @@ endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = conf include man test scripts \
libdaemon lib tools daemons libdm \
udev po liblvm python \
unit-tests/datastruct unit-tests/mm unit-tests/regex
udev po liblvm python
tools.distclean: test.distclean
endif
DISTCLEAN_DIRS += lcov_reports*
@ -97,7 +96,7 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test: all
$(MAKE) -C test $(@)
conf.generate man.generate: tools
@ -212,7 +211,7 @@ endif
endif
ifeq ("$(TESTING)", "yes")
include test/unit/Makefile
include unit-test/Makefile
endif
ifneq ($(shell which ctags),)

175
configure vendored
View File

@ -707,9 +707,7 @@ FSADM
ELDFLAGS
DM_LIB_PATCHLEVEL
DMEVENTD_PATH
AIO_LIBS
DL_LIBS
AIO
DEVMAPPER
DEFAULT_USE_LVMLOCKD
DEFAULT_USE_LVMPOLLD
@ -783,8 +781,6 @@ LOCKD_SANLOCK_LIBS
LOCKD_SANLOCK_CFLAGS
VALGRIND_LIBS
VALGRIND_CFLAGS
CUNIT_LIBS
CUNIT_CFLAGS
GENPNG
GENHTML
LCOV
@ -957,7 +953,6 @@ enable_profiling
enable_testing
enable_valgrind_pool
enable_devmapper
enable_aio
enable_lvmetad
enable_lvmpolld
enable_lvmlockd_sanlock
@ -1047,8 +1042,6 @@ DLM_CFLAGS
DLM_LIBS
SACKPT_CFLAGS
SACKPT_LIBS
CUNIT_CFLAGS
CUNIT_LIBS
VALGRIND_CFLAGS
VALGRIND_LIBS
LOCKD_SANLOCK_CFLAGS
@ -1707,7 +1700,6 @@ Optional Features:
--enable-testing enable testing targets in the makefile
--enable-valgrind-pool enable valgrind awareness of pools
--disable-devmapper disable LVM2 device-mapper interaction
--disable-aio disable asynchronous I/O
--enable-lvmetad enable the LVM Metadata Daemon
--enable-lvmpolld enable the LVM Polling Daemon
--enable-lvmlockd-sanlock
@ -1894,9 +1886,6 @@ Some influential environment variables:
SACKPT_CFLAGS
C compiler flags for SACKPT, overriding pkg-config
SACKPT_LIBS linker flags for SACKPT, overriding pkg-config
CUNIT_CFLAGS
C compiler flags for CUNIT, overriding pkg-config
CUNIT_LIBS linker flags for CUNIT, overriding pkg-config
VALGRIND_CFLAGS
C compiler flags for VALGRIND, overriding pkg-config
VALGRIND_LIBS
@ -3195,7 +3184,6 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
AIO=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
@ -3215,7 +3203,6 @@ case "$host_os" in
CLDNOWHOLEARCHIVE=
LIB_SUFFIX=dylib
DEVMAPPER=yes
AIO=no
ODIRECT=no
DM_IOCTLS=no
SELINUX=no
@ -11623,101 +11610,6 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESTING" >&5
$as_echo "$TESTING" >&6; }
if test "$TESTING" = yes; then
pkg_config_init
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CUNIT" >&5
$as_echo_n "checking for CUNIT... " >&6; }
if test -n "$CUNIT_CFLAGS"; then
pkg_cv_CUNIT_CFLAGS="$CUNIT_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_CUNIT_CFLAGS=`$PKG_CONFIG --cflags "cunit >= 2.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$CUNIT_LIBS"; then
pkg_cv_CUNIT_LIBS="$CUNIT_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_CUNIT_LIBS=`$PKG_CONFIG --libs "cunit >= 2.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
CUNIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
else
CUNIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$CUNIT_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (cunit >= 2.0) were not met:
$CUNIT_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables CUNIT_CFLAGS
and CUNIT_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
Alternatively, you may set the environment variables CUNIT_CFLAGS
and CUNIT_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
CUNIT_CFLAGS=$pkg_cv_CUNIT_CFLAGS
CUNIT_LIBS=$pkg_cv_CUNIT_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
fi
################################################################################
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
@ -11844,67 +11736,6 @@ $as_echo "#define DEVMAPPER_SUPPORT 1" >>confdefs.h
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use asynchronous I/O" >&5
$as_echo_n "checking whether to asynchronous I/O... " >&6; }
# Check whether --enable-aio was given.
if test "${enable_aio+set}" = set; then :
enableval=$enable_aio; AIO=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $AIO" >&5
$as_echo "$AIO" >&6; }
if test "$AIO" = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for io_setup in -laio" >&5
$as_echo_n "checking for io_setup in -laio... " >&6; }
if ${ac_cv_lib_aio_io_setup+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-laio $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char io_setup ();
int
main ()
{
return io_setup ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_aio_io_setup=yes
else
ac_cv_lib_aio_io_setup=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aio_io_setup" >&5
$as_echo "$ac_cv_lib_aio_io_setup" >&6; }
if test "x$ac_cv_lib_aio_io_setup" = xyes; then :
$as_echo "#define AIO_SUPPORT 1" >>confdefs.h
AIO_LIBS="-laio"
AIO_SUPPORT=yes
else
AIO_LIBS=
AIO_SUPPORT=no
fi
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build LVMetaD" >&5
$as_echo_n "checking whether to build LVMetaD... " >&6; }
@ -15854,13 +15685,11 @@ _ACEOF
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile unit-test/Makefile tools/Makefile udev/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -16634,7 +16463,7 @@ do
"scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
"test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;
"test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;;
"unit-test/Makefile") CONFIG_FILES="$CONFIG_FILES unit-test/Makefile" ;;
"tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
"udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;

View File

@ -1076,11 +1076,6 @@ AC_ARG_ENABLE(testing,
TESTING=$enableval, TESTING=no)
AC_MSG_RESULT($TESTING)
if test "$TESTING" = yes; then
pkg_config_init
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
fi
################################################################################
dnl -- Set LVM2 testsuite data
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
@ -2251,7 +2246,7 @@ scripts/lvmdump.sh
scripts/Makefile
test/Makefile
test/api/Makefile
test/unit/Makefile
unit-test/Makefile
tools/Makefile
udev/Makefile
])

257
doc/unit-tests.txt Normal file
View File

@ -0,0 +1,257 @@
Building unit tests
===================
make unit-unit/unit-test
Running unit tests
==================
The tests leave no artifacts at the moment, so you can just run
unit-test/unit-test from wherever you want.
./unit-test <list|run> [pattern]
Listing tests
-------------
Every test has a symbolic path associated with it. Just like file paths they
are split into components separated by '/'s. The 'list' command will show you
a tree of these tests, along with some description text.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list
base
data-struct
bitset
and ................................................. and all bits
equal ............................................... equality
get_next ............................................ get next set bit
list
splice .............................................. joining lists together
string
asprint ............................................. tests asprint
strncpy ............................................. tests string copying
device
bcache
block-size-multiple-page ............................ block size must be a multiple of page size
block-size-positive ................................. block size must be positive
blocks-get-evicted .................................. block get evicted with many reads
cache-blocks-positive ............................... nr cache blocks must be positive
create-destroy ...................................... simple create/destroy
flush-waits ......................................... flush waits for all dirty
get-reads ........................................... bcache_get() triggers read
prefetch-never-waits ................................ too many prefetches does not trigger a wait
prefetch-reads ...................................... prefetch issues a read
read-multiple-files ................................. read from multiple files
reads-cached ........................................ repeated reads are cached
writeback-occurs .................................... dirty data gets written back
zero-flag-dirties ................................... zeroed data counts as dirty
formatting
percent
0 ................................................... Pretty printing of percentages near 0%
100 ................................................. Pretty printing of percentages near 100%
regex
fingerprints .......................................... not sure
matching .............................................. test the matcher with a variety of regexes
dm
target
mirror
status .............................................. parsing mirror status
metadata
config
cascade ............................................... cascade
clone ................................................. duplicating a config tree
parse ................................................. parsing various
An optional 'pattern' argument may be specified to select subsets of tests.
This pattern is a posix regex and does a substring match, so you will need to
use anchors if you particularly want the match at the beginning or end of the
string.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list data-struct
base
data-struct
bitset
and ................................................. and all bits
equal ............................................... equality
get_next ............................................ get next set bit
list
splice .............................................. joining lists together
string
asprint ............................................. tests asprint
strncpy ............................................. tests string copying
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list s$
base
device
bcache
flush-waits ......................................... flush waits for all dirty
get-reads ........................................... bcache_get() triggers read
prefetch-never-waits ................................ too many prefetches does not trigger a wait
prefetch-reads ...................................... prefetch issues a read
read-multiple-files ................................. read from multiple files
writeback-occurs .................................... dirty data gets written back
zero-flag-dirties ................................... zeroed data counts as dirty
regex
fingerprints .......................................... not sure
dm
target
mirror
status .............................................. parsing mirror status
Running tests
=============
'make run-unit-test' from the top level will run all unit tests. But I tend to
run it by hand to I can select just the tests I'm working on.
Use the 'run' command to run the tests. Currently all logging goes to stderr,
so the test runner prints a line at the start of the test and a line
indicating success or failure at the end.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run bcache/block-size
[RUN ] /base/device/bcache/block-size-multiple-page
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
[ OK] /base/device/bcache/block-size-multiple-page
[RUN ] /base/device/bcache/block-size-positive
bcache must have a non zero block size
[ OK] /base/device/bcache/block-size-positive
2/2 tests passed
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run data-struct
[RUN ] /base/data-struct/bitset/and
[ OK] /base/data-struct/bitset/and
[RUN ] /base/data-struct/bitset/equal
[ OK] /base/data-struct/bitset/equal
[RUN ] /base/data-struct/bitset/get_next
[ OK] /base/data-struct/bitset/get_next
[RUN ] /base/data-struct/list/splice
[ OK] /base/data-struct/list/splice
[RUN ] /base/data-struct/string/asprint
[ OK] /base/data-struct/string/asprint
[RUN ] /base/data-struct/string/strncpy
[ OK] /base/data-struct/string/strncpy
6/6 tests passed
Writing tests
=============
[See unit-test/framework.h and unit-test/units.h for the details]
Tests are grouped together into 'suites', all tests in a suite share a
'fixture'. A fixture is a void * to any object you want; use it to set up any
common environment that you need for the tests to run (eg, creating a dm_pool).
Test suites have nothing to do with the test paths, you can have tests from
different suites with similar paths, the runner sorts things for you.
Put your tests in a file in unit-test/, with '_t' at the end of the name
(convention only, nothing relies on this).
#include "units.h"
Then write any fixtures you need:
eg,
static void *_mem_init(void) {
struct dm_pool *mem = dm_pool_create("bitset test", 1024);
if (!mem) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return mem;
}
static void _mem_exit(void *mem)
{
dm_pool_destroy(mem);
}
Then write your tests, which should take the void * that was returned by your
fixture. Use the T_ASSERT* macros to indicate failure.
eg,
static void test_equal(void *fixture)
{
struct dm_pool *mem = fixture;
dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
int i, j;
for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
dm_bit_set(bs1, i);
dm_bit_set(bs2, i);
}
T_ASSERT(dm_bitset_equal(bs1, bs2));
T_ASSERT(dm_bitset_equal(bs2, bs1));
for (i = 0; i < NR_BITS; i++) {
bit_flip(bs1, i);
T_ASSERT(!dm_bitset_equal(bs1, bs2));
T_ASSERT(!dm_bitset_equal(bs2, bs1));
T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
bit_flip(bs1, i);
}
}
At the end of your test file you should write a function that builds one or
more test suites and adds them to the list of all suites that is passed in. I
tend to write a little macro (T) to save typing the same test path repeatedly.
eg,
#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
void bitset_tests(struct dm_list *all_tests)
{
struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
if (!ts) {
fprintf(stderr, "out of memory\n");
exit(1);
}
T("get_next", "get next set bit", test_get_next);
T("equal", "equality", test_equal);
T("and", "and all bits", test_and);
dm_list_add(all_tests, &ts->list);
}
Then you need to declare your registration function and call it in units.h.
// Declare the function that adds tests suites here ...
...
void bitset_tests(struct dm_list *suites);
...
// ... and call it in here.
static inline void register_all_tests(struct dm_list *suites)
{
...
bitset_tests(suites);
...
}
Finally add your test file to the Makefile.in and rerun configure.

View File

@ -1,40 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Merely wraps the logger library with a bit of standard policy.
require 'logger'
module Log
$log = Logger.new(STDERR)
def init(io_)
$log = Logger.new(io_)
end
end
def fatal(*args)
$log.fatal(*args)
end
def error(*args)
$log.error(*args)
end
def info(*args)
$log.info(*args)
end
def warning(*args)
$log.warn(*args)
end
def debug(*args)
$log.debug(*args)
end

View File

@ -1,38 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Policy for the location of report templates
require 'string-store'
class TemplateStringStore < StringStore
def initialize()
super(['report-generators/templates'])
end
end
module ReportTemplates
def generate_report(report, bs, dest_path = nil)
include Reports
reports = ReportRegister.new
template_store = TemplateStringStore.new
report = reports.get_report(report)
erb = ERB.new(template_store.lookup(report.template))
body = erb.result(bs)
title = report.short_desc
erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
txt = erb.result(binding)
dest_path = dest_path.nil? ? report.path : dest_path
dest_path.open("w") do |out|
out.puts txt
end
end
end

View File

@ -1,58 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Data about the various reports we support
require 'log'
require 'pathname'
module Reports
Report = Struct.new(:short_desc, :desc, :path, :template)
class ReportRegister
attr_reader :reports
private
def add_report(sym, *args)
@reports[sym] = Report.new(*args)
end
public
def initialize()
@reports = Hash.new
add_report(:unit_test,
"Unit Tests",
"unit tests",
Pathname.new("reports/unit.html"),
Pathname.new("unit_test.rhtml"))
add_report(:memcheck,
"Memory Tests",
"unit tests with valgrind memory checking",
Pathname.new("reports/memcheck.html"),
Pathname.new("memcheck.rhtml"))
add_report(:unit_detail,
"Unit Test Detail",
"unit test detail",
Pathname.new("reports/unit_detail.html"), # FIXME replace this with a lambda
Pathname.new("unit_detail.rhtml"))
end
def get_report(sym)
raise RuntimeError, "unknown report '#{sym}'" unless @reports.member?(sym)
@reports[sym]
end
def each(&block)
@reports.each(&block)
end
end
end

View File

@ -1,56 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Parses the simple colon delimited test schedule files.
ScheduledTest = Struct.new(:desc, :command_line, :status, :output)
class Schedule
attr_reader :dir, :schedules
def initialize(dir, ss)
@dir = dir
@schedules = ss
end
def run
Dir::chdir(@dir.to_s) do
@schedules.each do |s|
reader, writer = IO.pipe
print "#{s.desc} ... "
pid = spawn(s.command_line, [ STDERR, STDOUT ] => writer)
writer.close
_, s.status = Process::waitpid2(pid)
puts (s.status.success? ? "pass" : "fail")
s.output = reader.read
end
end
end
def self.read(dir, io)
ss = Array.new
io.readlines.each do |line|
case line.strip
when /^\#.*/
next
when /([^:]+):(.*)/
ss << ScheduledTest.new($1.strip, $2.strip)
else
raise RuntimeError, "badly formatted schedule line"
end
end
Schedule.new(dir, ss)
end
end

View File

@ -1,42 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Provides a simple way of accessing the contents of files by a symbol
# name. Useful for erb templates.
require 'pathname'
class StringStore
attr_accessor :path
def initialize(p)
@paths = p.nil? ? Array.new : p # FIXME: do we need to copy p ?
end
def lookup(sym)
files = expansions(sym)
@paths.each do |p|
files.each do |f|
pn = Pathname.new("#{p}/#{f}")
if pn.file?
return pn.read
end
end
end
raise RuntimeError, "unknown string entry: #{sym}"
end
private
def expansions(sym)
["#{sym}", "#{sym}.txt"]
end
end

View File

@ -1,86 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Reads the schedule files given on the command line. Runs them and
# generates the reports.
# FIXME: a lot of duplication with unit_test.rb
require 'schedule_file'
require 'pathname'
require 'reports'
require 'erb'
require 'report_templates'
include ReportTemplates
schedules = ARGV.map do |f|
p = Pathname.new(f)
Schedule.read(p.dirname, p)
end
total_passed = 0
total_failed = 0
# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
ENV['TEST_TOOL'] = "valgrind --leak-check=full --show-reachable=yes"
schedules.each do |s|
s.run
s.schedules.each do |t|
if t.status.success?
total_passed += 1
else
total_failed += 1
end
end
end
def mangle(txt)
txt.gsub(/\s+/, '_')
end
MemcheckStats = Struct.new(:definitely_lost, :indirectly_lost, :possibly_lost, :reachable)
def format(bytes, blocks)
"#{bytes} bytes, #{blocks} blocks"
end
# Examines the output for details of leaks
def extract_stats(t)
d = i = p = r = '-'
t.output.split("\n").each do |l|
case l
when /==\d+== definitely lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
d = format($1, $2)
when /==\d+== indirectly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
i = format($1, $2)
when /==\d+== possibly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
p = format($1, $2)
when /==\d+== still reachable: ([0-9,]+) bytes in ([0-9,]+) blocks/
r = format($1, $2)
end
end
MemcheckStats.new(d, i, p, r)
end
generate_report(:memcheck, binding)
# now we generate a detail report for each schedule
schedules.each do |s|
s.schedules.each do |t|
generate_report(:unit_detail, binding, Pathname.new("reports/memcheck_#{mangle(t.desc)}.html"))
end
end

View File

@ -1,25 +0,0 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title><%= title %></title>
<link title="Style" type="text/css" rel="stylesheet" href="stylesheet.css">
</head>
<body>
<div id="banner">
<h2><%= title %></h2>
</div>
<div id="main">
<div id="controls">
<table>
<tr><td><a href="index.html">Generation times</a></td></tr>
<tr><td><a href="unit.html">Unit tests</a></td></tr>
<tr><td><a href="memcheck.html">Memory tests</a></td></tr>
</table>
</div>
<div id="body">
<%= body %>
</div>
</div>
</body>

View File

@ -1,17 +0,0 @@
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Report</th><th>Generation time</th></tr>
<% [:unit_test, :memcheck].each do |sym| %>
<% r = reports.get_report(sym) %>
<tr>
<td>
<% if r.path.file? %>
<a href="<%= r.path.to_s.gsub(/^reports\//, '') %>"><%= r.short_desc %></a>
<% else %>
<%= r.short_desc %>
<% end %>
</td>
<td><%= safe_mtime(r) %></td>
</tr>
<% end %>
</table>

View File

@ -1,30 +0,0 @@
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Tests passed</th><th>Tests failed</th></tr>
<tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
</table>
<% schedules.each do |s| %>
<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Test</th><th>Result</th><th>Definitely lost</th><th>indirectly lost</th><th>possibly lost</th><th>still reachable</th><tr>
<% s.schedules.each do |t| %>
<tr>
<td>
<a href="memcheck_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
</td>
<% if t.status.success? %>
<td class="pass">pass</td>
<% else %>
<td class="fail">fail</td>
<% end %>
<% stats = extract_stats(t) %>
<td><%= stats.definitely_lost %></td>
<td><%= stats.indirectly_lost %></td>
<td><%= stats.possibly_lost %></td>
<td><%= stats.reachable %></td>
</tr>
<% end %>
</table>
<% end %>

View File

@ -1,37 +0,0 @@
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Test</th><th>Result</th></tr>
<tr>
<td>
<%= t.desc %>
</td>
<% if t.status.success? %>
<td class="pass">pass</td>
<% else %>
<td class="fail">fail</td>
<% end %>
</tr>
</table>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Command line</th></tr>
<tr>
<td>
<pre>
<%= t.command_line %>
</pre>
</td>
</tr>
</table>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Output</th></tr>
<tr>
<td>
<pre>
<%= t.output %>
</pre>
</td>
</tr>
</table>

View File

@ -1,23 +0,0 @@
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Tests passed</th><th>Tests failed</th></tr>
<tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
</table>
<% schedules.each do |s| %>
<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
<tr><th>Test</th><th>Result</th></tr>
<% s.schedules.each do |t| %>
<tr>
<td>
<a href="detail_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
</td>
<% if t.status.success? %>
<td class="pass">pass</td>
<% else %>
<td class="fail">fail</td>
<% end %>
</tr>
<% end %>
</table>
<% end %>

View File

@ -1,4 +0,0 @@
# This is a comment
description number 1:$TEST_TOOL ls
foo bar: $TEST_TOOL du -hs .
this comment is prefixed with whitespace: $TEST_TOOL date

View File

@ -1 +0,0 @@
Hello, world!

View File

@ -1,3 +0,0 @@
one
two
three

View File

@ -1,36 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
require 'test/unit'
require 'stringio'
require 'log'
class TestLog < Test::Unit::TestCase
include Log
private
def remove_timestamps(l)
l.gsub(/\[[^\]]*\]/, '')
end
public
def test_log
StringIO.open do |out|
init(out)
info("msg1")
warning("msg2")
debug("msg3")
assert_equal("I, INFO -- : msg1\nW, WARN -- : msg2\nD, DEBUG -- : msg3\n",
remove_timestamps(out.string))
end
end
end

View File

@ -1,38 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
require 'test/unit'
require 'pathname'
require 'schedule_file'
class TestScheduleFile < Test::Unit::TestCase
def test_reading
p = Pathname.new("report-generators/test/example.schedule")
p.open do |f|
s = Schedule.read(p.dirname, f)
assert_equal(3, s.schedules.size)
assert_equal(s.schedules[2].desc, "this comment is prefixed with whitespace")
assert_equal(s.schedules[0].command_line, "$TEST_TOOL ls")
end
end
def test_running
p = Pathname.new("report-generators/test/example.schedule")
p.open do |f|
s = Schedule.read(p.dirname, f)
s.run
s.schedules.each do |t|
assert(t.status.success?)
end
end
end
end

View File

@ -1,29 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
require 'string-store'
require 'test/unit'
class TestStringStore < Test::Unit::TestCase
def setup
@ss = StringStore.new(['report-generators/test/strings',
'report-generators/test/strings/more_strings'])
end
def test_lookup
assert_equal("Hello, world!\n", @ss.lookup(:test1))
assert_equal("one\ntwo\nthree", @ss.lookup(:test2))
assert_equal("lorem\n", @ss.lookup(:test3))
assert_raises(RuntimeError) do
@ss.lookup(:unlikely_name)
end
end
end

View File

@ -1,13 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
require 'tc_log'
require 'tc_string_store'
require 'tc_schedule_file'

View File

@ -1,42 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# This generates the index for the reports, including generation
# times.
require 'log'
require 'string-store'
require 'reports'
require 'erb'
require 'report_templates'
include Reports
reports = ReportRegister.new
def safe_mtime(r)
r.path.file? ? r.path.mtime.to_s : "not generated"
end
template_store = TemplateStringStore.new
# FIXME: use generate_report() method
erb = ERB.new(template_store.lookup("index.rhtml"))
body = erb.result(binding)
title = "Generation times"
erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
txt = erb.result(binding)
Pathname.new("reports/index.html").open("w") do |f|
f.puts txt
end

View File

@ -1,56 +0,0 @@
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Reads the schedule files given on the command line. Runs them and
# generates the reports.
require 'schedule_file'
require 'pathname'
require 'reports'
require 'erb'
require 'report_templates'
include ReportTemplates
schedules = ARGV.map do |f|
p = Pathname.new(f)
Schedule.read(p.dirname, p)
end
total_passed = 0
total_failed = 0
# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
schedules.each do |s|
s.run
s.schedules.each do |t|
if t.status.success?
total_passed += 1
else
total_failed += 1
end
end
end
def mangle(txt)
txt.gsub(/\s+/, '_')
end
generate_report(:unit_test, binding)
# now we generate a detail report for each schedule
schedules.each do |s|
s.schedules.each do |t|
generate_report(:unit_detail, binding, Pathname.new("reports/detail_#{mangle(t.desc)}.html"))
end
end

View File

@ -1,77 +0,0 @@
/* Styles for main page */
#banner {
background: #9c9;
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 2px solid;
font: small-caps 20px/20px "Times New Roman", serif;
color: #282;
text-align: center;
}
#banner img {
float: left;
}
#main {
margin-left: 0em;
padding-top: 4ex;
padding-left: 2em;
background: white;
}
h1 {
font: 150% sans-serif;
color: #226;
border-bottom: 3px dotted #77d;
}
body {
font: normal 75% verdana,arial,helvetica;
color:#000000;
}
table tr td, table tr th {
font-size: 75%;
}
table.stripes tr th {
font-weight: bold;
text-align: left;
background: #a0a0a0;
}
table.stripes tr td {
background: #ccccc0;
}
td.pass {
color: green;
}
td.fail {
color: red;
font-weight: bold;
}
#main {
padding-left: 0em;
}
#controls {
float: left;
padding-top: 1em;
padding-left: 1em;
padding-right: 1em;
padding-bottom: 1em;
width: 14em;
border-right: 2px solid;
}
#body {
margin-left: 16em;
padding-top: 4ex;
padding-left: 2em;
background: white;
border-left: 2px solid;
}

View File

@ -1,152 +0,0 @@
/*
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "units.h"
static struct dm_pool *mem;
int config_init(void) {
mem = dm_pool_create("config test", 1024);
return mem == NULL;
}
int config_fini(void) {
dm_pool_destroy(mem);
return 0;
}
static const char *conf =
"id = \"yada-yada\"\n"
"seqno = 15\n"
"status = [\"READ\", \"WRITE\"]\n"
"flags = []\n"
"extent_size = 8192\n"
"physical_volumes {\n"
" pv0 {\n"
" id = \"abcd-efgh\"\n"
" }\n"
" pv1 {\n"
" id = \"bbcd-efgh\"\n"
" }\n"
" pv2 {\n"
" id = \"cbcd-efgh\"\n"
" }\n"
"}\n";
static const char *overlay =
"id = \"yoda-soda\"\n"
"flags = [\"FOO\"]\n"
"physical_volumes {\n"
" pv1 {\n"
" id = \"hgfe-dcba\"\n"
" }\n"
" pv3 {\n"
" id = \"dbcd-efgh\"\n"
" }\n"
"}\n";
static void test_parse(void)
{
struct dm_config_tree *tree = dm_config_from_string(conf);
const struct dm_config_value *value;
CU_ASSERT((long) tree);
CU_ASSERT(dm_config_has_node(tree->root, "id"));
CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes"));
CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0"));
CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0/id"));
CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada"));
CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "idt", "foo"), "foo"));
CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo"));
CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
CU_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL));
CU_ASSERT(dm_config_get_uint32(tree->root, "extent_size", NULL));
/* FIXME: Currently everything parses as a list, even if it's not */
// CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
// CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
CU_ASSERT(dm_config_get_list(tree->root, "flags", &value));
CU_ASSERT(value->next == NULL); /* an empty list */
CU_ASSERT(dm_config_get_list(tree->root, "status", &value));
CU_ASSERT(value->next != NULL); /* a non-empty list */
dm_config_destroy(tree);
}
static void test_clone(void)
{
struct dm_config_tree *tree = dm_config_from_string(conf);
struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1);
const struct dm_config_value *value;
/* Check that the nodes are actually distinct. */
CU_ASSERT(n != tree->root);
CU_ASSERT(n->sib != tree->root->sib);
CU_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL);
CU_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL);
CU_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes"));
CU_ASSERT(dm_config_has_node(n, "id"));
CU_ASSERT(dm_config_has_node(n, "physical_volumes"));
CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0"));
CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id"));
CU_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada"));
CU_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo"));
CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo"));
CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
CU_ASSERT(!dm_config_get_uint32(n, "id", NULL));
CU_ASSERT(dm_config_get_uint32(n, "extent_size", NULL));
/* FIXME: Currently everything parses as a list, even if it's not */
// CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
// CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
CU_ASSERT(dm_config_get_list(n, "flags", &value));
CU_ASSERT(value->next == NULL); /* an empty list */
CU_ASSERT(dm_config_get_list(n, "status", &value));
CU_ASSERT(value->next != NULL); /* a non-empty list */