diff options
Diffstat (limited to 'src/libstrongswan/tests')
20 files changed, 1120 insertions, 285 deletions
diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 331a5480d..e8e8090f3 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -42,6 +42,7 @@ tests_SOURCES = tests.h tests.c \ suites/test_host.c \ suites/test_hasher.c \ suites/test_crypter.c \ + suites/test_crypto_factory.c \ suites/test_pen.c \ suites/test_asn1.c \ suites/test_asn1_parser.c \ @@ -52,7 +53,7 @@ tests_SOURCES = tests.h tests.c \ tests_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libstrongswan/tests \ - -DPLUGINDIR=\""$(top_builddir)/src/libstrongswan/plugins\"" \ + -DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \ -DPLUGINS=\""${s_plugins}\"" \ @COVERAGE_CFLAGS@ diff --git a/src/libstrongswan/tests/Makefile.in b/src/libstrongswan/tests/Makefile.in index e58831c5b..1d2d5ebd1 100644 --- a/src/libstrongswan/tests/Makefile.in +++ b/src/libstrongswan/tests/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -138,6 +138,7 @@ am_tests_OBJECTS = tests-tests.$(OBJEXT) \ suites/tests-test_host.$(OBJEXT) \ suites/tests-test_hasher.$(OBJEXT) \ suites/tests-test_crypter.$(OBJEXT) \ + suites/tests-test_crypto_factory.$(OBJEXT) \ suites/tests-test_pen.$(OBJEXT) \ suites/tests-test_asn1.$(OBJEXT) \ suites/tests-test_asn1_parser.$(OBJEXT) \ @@ -295,6 +296,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -313,6 +315,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -340,6 +343,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -431,6 +435,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -479,6 +484,7 @@ tests_SOURCES = tests.h tests.c \ suites/test_host.c \ suites/test_hasher.c \ suites/test_crypter.c \ + suites/test_crypto_factory.c \ suites/test_pen.c \ suites/test_asn1.c \ suites/test_asn1_parser.c \ @@ -489,7 +495,7 @@ tests_SOURCES = tests.h tests.c \ tests_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libstrongswan/tests \ - -DPLUGINDIR=\""$(top_builddir)/src/libstrongswan/plugins\"" \ + -DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \ -DPLUGINS=\""${s_plugins}\"" \ @COVERAGE_CFLAGS@ @@ -613,6 +619,8 @@ suites/tests-test_hasher.$(OBJEXT): suites/$(am__dirstamp) \ suites/$(DEPDIR)/$(am__dirstamp) suites/tests-test_crypter.$(OBJEXT): suites/$(am__dirstamp) \ suites/$(DEPDIR)/$(am__dirstamp) +suites/tests-test_crypto_factory.$(OBJEXT): suites/$(am__dirstamp) \ + suites/$(DEPDIR)/$(am__dirstamp) suites/tests-test_pen.$(OBJEXT): suites/$(am__dirstamp) \ suites/$(DEPDIR)/$(am__dirstamp) suites/tests-test_asn1.$(OBJEXT): suites/$(am__dirstamp) \ @@ -649,6 +657,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_bio_writer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_chunk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_crypter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_crypto_factory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_ecdsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_enum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@suites/$(DEPDIR)/tests-test_enumerator.Po@am__quote@ @@ -1039,6 +1048,20 @@ suites/tests-test_crypter.obj: suites/test_crypter.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -c -o suites/tests-test_crypter.obj `if test -f 'suites/test_crypter.c'; then $(CYGPATH_W) 'suites/test_crypter.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_crypter.c'; fi` +suites/tests-test_crypto_factory.o: suites/test_crypto_factory.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -MT suites/tests-test_crypto_factory.o -MD -MP -MF suites/$(DEPDIR)/tests-test_crypto_factory.Tpo -c -o suites/tests-test_crypto_factory.o `test -f 'suites/test_crypto_factory.c' || echo '$(srcdir)/'`suites/test_crypto_factory.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/tests-test_crypto_factory.Tpo suites/$(DEPDIR)/tests-test_crypto_factory.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_crypto_factory.c' object='suites/tests-test_crypto_factory.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -c -o suites/tests-test_crypto_factory.o `test -f 'suites/test_crypto_factory.c' || echo '$(srcdir)/'`suites/test_crypto_factory.c + +suites/tests-test_crypto_factory.obj: suites/test_crypto_factory.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -MT suites/tests-test_crypto_factory.obj -MD -MP -MF suites/$(DEPDIR)/tests-test_crypto_factory.Tpo -c -o suites/tests-test_crypto_factory.obj `if test -f 'suites/test_crypto_factory.c'; then $(CYGPATH_W) 'suites/test_crypto_factory.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_crypto_factory.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/tests-test_crypto_factory.Tpo suites/$(DEPDIR)/tests-test_crypto_factory.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='suites/test_crypto_factory.c' object='suites/tests-test_crypto_factory.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -c -o suites/tests-test_crypto_factory.obj `if test -f 'suites/test_crypto_factory.c'; then $(CYGPATH_W) 'suites/test_crypto_factory.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_crypto_factory.c'; fi` + suites/tests-test_pen.o: suites/test_pen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_CFLAGS) $(CFLAGS) -MT suites/tests-test_pen.o -MD -MP -MF suites/$(DEPDIR)/tests-test_pen.Tpo -c -o suites/tests-test_pen.o `test -f 'suites/test_pen.c' || echo '$(srcdir)/'`suites/test_pen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) suites/$(DEPDIR)/tests-test_pen.Tpo suites/$(DEPDIR)/tests-test_pen.Po diff --git a/src/libstrongswan/tests/suites/test_asn1.c b/src/libstrongswan/tests/suites/test_asn1.c index d0cd7e6e4..ac7c5519e 100644 --- a/src/libstrongswan/tests/suites/test_asn1.c +++ b/src/libstrongswan/tests/suites/test_asn1.c @@ -335,8 +335,8 @@ START_TEST(test_asn1_length) /* largest chunk on 32 bit system */ a = chunk_from_chars(0x04, 0x84, 0xff, 0xff, 0xff, 0xf9, 0xaa); - a.len = 4294967295; - ck_assert(asn1_length(&a) == 4294967289); + a.len = 4294967295U; + ck_assert(asn1_length(&a) == 4294967289U); } END_TEST diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index 34ace2894..b33d70ec7 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -790,7 +790,11 @@ END_TEST START_TEST(test_chunk_map) { chunk_t *map, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); +#ifdef WIN32 + char *path = "C:\\Windows\\Temp\\strongswan-chunk-map-test"; +#else char *path = "/tmp/strongswan-chunk-map-test"; +#endif ck_assert(chunk_write(contents, path, 022, TRUE)); @@ -827,7 +831,11 @@ END_TEST START_TEST(test_chunk_from_fd_file) { chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); +#ifdef WIN32 + char *path = "C:\\Windows\\Temp\\strongswan-chunk-fd-test"; +#else char *path = "/tmp/strongswan-chunk-fd-test"; +#endif int fd; ck_assert(chunk_write(contents, path, 022, TRUE)); @@ -849,7 +857,7 @@ START_TEST(test_chunk_from_fd_skt) int s[2]; ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0); - ck_assert(write(s[1], contents.ptr, contents.len) == contents.len); + ck_assert_int_eq(send(s[1], contents.ptr, contents.len, 0), contents.len); close(s[1]); ck_assert_msg(chunk_from_fd(s[0], &in), "%s", strerror(errno)); close(s[0]); @@ -866,7 +874,7 @@ void *chunk_from_fd_run(void *data) for (i = 0; i < FROM_FD_COUNT; i++) { - ck_assert(write(fd, &i, sizeof(i)) == sizeof(i)); + ck_assert(send(fd, &i, sizeof(i), 0) == sizeof(i)); } close(fd); return NULL; diff --git a/src/libstrongswan/tests/suites/test_crypto_factory.c b/src/libstrongswan/tests/suites/test_crypto_factory.c new file mode 100644 index 000000000..94f45dada --- /dev/null +++ b/src/libstrongswan/tests/suites/test_crypto_factory.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "test_suite.h" + +#include <crypto/crypto_factory.h> + +static rng_t *rng_create(rng_quality_t quality) +{ + rng_quality_t *q = malloc_thing(rng_quality_t); + *q = quality; + return (rng_t*)q; +} + +static rng_t *rng_create_weak(rng_quality_t quality) +{ + ck_assert(quality == RNG_WEAK); + return rng_create(RNG_WEAK); +} + +static rng_t *rng_create_strong(rng_quality_t quality) +{ + ck_assert(quality <= RNG_STRONG); + return rng_create(RNG_STRONG); +} + +static rng_t *rng_create_true(rng_quality_t quality) +{ + ck_assert(quality <= RNG_TRUE); + return rng_create(RNG_TRUE); +} + +static rng_t *rng_create_true_second(rng_quality_t quality) +{ + fail("should never be called"); + return rng_create(RNG_TRUE); +} + +static rng_quality_t rng_weak = RNG_WEAK; +static rng_quality_t rng_strong = RNG_STRONG; +static rng_quality_t rng_true = RNG_TRUE; + +static struct { + rng_quality_t *exp_weak; + rng_quality_t *exp_strong; + rng_quality_t *exp_true; + struct { + rng_quality_t *q; + rng_constructor_t create; + } data[4]; +} rng_data[] = { + { NULL, NULL, NULL, { + { NULL, NULL } + }}, + { &rng_weak, NULL, NULL, { + { &rng_weak, rng_create_weak }, + { NULL, NULL } + }}, + { &rng_strong, &rng_strong, NULL, { + { &rng_strong, rng_create_strong }, + { NULL, NULL } + }}, + { &rng_true, &rng_true, &rng_true, { + { &rng_true, rng_create_true }, + { NULL, NULL } + }}, + { &rng_true, &rng_true, &rng_true, { + { &rng_true, rng_create_true }, + { &rng_true, rng_create_true_second }, + { NULL, NULL } + }}, + { &rng_weak, &rng_true, &rng_true, { + { &rng_weak, rng_create_weak }, + { &rng_true, rng_create_true }, + { NULL, NULL } + }}, + { &rng_weak, &rng_strong, &rng_true, { + { &rng_true, rng_create_true }, + { &rng_strong, rng_create_strong }, + { &rng_weak, rng_create_weak }, + { NULL, NULL } + }}, + { &rng_weak, &rng_strong, &rng_true, { + { &rng_weak, rng_create_weak }, + { &rng_strong, rng_create_strong }, + { &rng_true, rng_create_true }, + { NULL, NULL } + }}, +}; + +static void verify_rng(crypto_factory_t *factory, rng_quality_t request, + rng_quality_t *expected) +{ + rng_quality_t *res; + + res = (rng_quality_t*)factory->create_rng(factory, request); + if (!expected) + { + ck_assert(!res); + } + else + { + ck_assert(res); + ck_assert_int_eq(*expected, *res); + free(res); + } +} + +START_TEST(test_create_rng) +{ + crypto_factory_t *factory; + int i; + + factory = crypto_factory_create(); + for (i = 0; rng_data[_i].data[i].q; i++) + { + ck_assert(factory->add_rng(factory, *rng_data[_i].data[i].q, "test", + rng_data[_i].data[i].create)); + } + verify_rng(factory, RNG_WEAK, rng_data[_i].exp_weak); + verify_rng(factory, RNG_STRONG, rng_data[_i].exp_strong); + verify_rng(factory, RNG_TRUE, rng_data[_i].exp_true); + for (i = 0; rng_data[_i].data[i].q; i++) + { + factory->remove_rng(factory, rng_data[_i].data[i].create); + } + factory->destroy(factory); +} +END_TEST + +static diffie_hellman_t *dh_create(char *plugin) +{ + return (diffie_hellman_t*)plugin; +} + +static diffie_hellman_t *dh_create_modp1024(diffie_hellman_group_t group, ...) +{ + ck_assert(group == MODP_1024_BIT); + return dh_create("plugin1"); +} + +static diffie_hellman_t *dh_create_modp1024_second(diffie_hellman_group_t group, + ...) +{ + ck_assert(group == MODP_1024_BIT); + return dh_create("plugin2"); +} + +static diffie_hellman_t *dh_create_modp2048(diffie_hellman_group_t group, ...) +{ + ck_assert(group == MODP_2048_BIT); + return dh_create("plugin1"); +} + +static diffie_hellman_t *dh_create_modp2048_second(diffie_hellman_group_t group, + ...) +{ + ck_assert(group == MODP_2048_BIT); + return dh_create("plugin2"); +} + +static struct { + char *exp1024; + char *exp2048; + struct { + diffie_hellman_group_t g; + dh_constructor_t create; + char *plugin; + } data[4]; +} dh_data[] = { + { NULL, NULL, { + { MODP_NONE, NULL, NULL } + }}, + { "plugin1", NULL, { + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_NONE, NULL, NULL } + }}, + { "plugin1", NULL, { + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_1024_BIT, dh_create_modp1024_second, "plugin2" }, + { MODP_NONE, NULL, NULL } + }}, + { "plugin2", NULL, { + { MODP_1024_BIT, dh_create_modp1024_second, "plugin2" }, + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_NONE, NULL, NULL } + }}, + { "plugin1", "plugin1", { + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, + { MODP_NONE, NULL } + }}, + { "plugin1", "plugin1", { + { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_NONE, NULL } + }}, + { "plugin1", "plugin1", { + { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, + { MODP_2048_BIT, dh_create_modp2048_second, "plugin2" }, + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_NONE, NULL } + }}, + { "plugin1", "plugin2", { + { MODP_2048_BIT, dh_create_modp2048_second, "plugin2" }, + { MODP_2048_BIT, dh_create_modp2048, "plugin1" }, + { MODP_1024_BIT, dh_create_modp1024, "plugin1" }, + { MODP_NONE, NULL } + }}, +}; + +static void verify_dh(crypto_factory_t *factory, diffie_hellman_group_t request, + char *expected) +{ + char *plugin; + + plugin = (char*)factory->create_dh(factory, request); + if (!expected) + { + ck_assert(!plugin); + } + else + { + ck_assert(plugin); + ck_assert_str_eq(expected, plugin); + } +} + +START_TEST(test_create_dh) +{ + enumerator_t *enumerator; + crypto_factory_t *factory; + diffie_hellman_group_t group; + char *plugin; + int i, len = 0; + + + factory = crypto_factory_create(); + for (i = 0; dh_data[_i].data[i].g != MODP_NONE; i++) + { + ck_assert(factory->add_dh(factory, dh_data[_i].data[i].g, + dh_data[_i].data[i].plugin, + dh_data[_i].data[i].create)); + } + verify_dh(factory, MODP_1024_BIT, dh_data[_i].exp1024); + verify_dh(factory, MODP_2048_BIT, dh_data[_i].exp2048); + + len = countof(dh_data[_i].data); + enumerator = factory->create_dh_enumerator(factory); + for (i = 0; enumerator->enumerate(enumerator, &group, &plugin) && i < len;) + { + ck_assert_int_eq(dh_data[_i].data[i].g, group); + while (dh_data[_i].data[i].g == group) + { /* skip other entries by the same group */ + i++; + } + switch (group) + { + case MODP_1024_BIT: + ck_assert(dh_data[_i].exp1024); + ck_assert_str_eq(dh_data[_i].exp1024, plugin); + break; + case MODP_2048_BIT: + ck_assert(dh_data[_i].exp2048); + ck_assert_str_eq(dh_data[_i].exp2048, plugin); + break; + default: + fail("unexpected DH group"); + break; + } + } + ck_assert(!enumerator->enumerate(enumerator)); + ck_assert_int_eq(dh_data[_i].data[i].g, MODP_NONE); + enumerator->destroy(enumerator); + + for (i = 0; dh_data[_i].data[i].g != MODP_NONE; i++) + { + factory->remove_dh(factory, dh_data[_i].data[i].create); + } + factory->destroy(factory); +} +END_TEST + +Suite *crypto_factory_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("crypto-factory"); + + tc = tcase_create("create_rng"); + tcase_add_loop_test(tc, test_create_rng, 0, countof(rng_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("create_dh"); + tcase_add_loop_test(tc, test_create_dh, 0, countof(dh_data)); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/suites/test_enum.c b/src/libstrongswan/tests/suites/test_enum.c index 990d9cfad..b48b51c0e 100644 --- a/src/libstrongswan/tests/suites/test_enum.c +++ b/src/libstrongswan/tests/suites/test_enum.c @@ -15,7 +15,6 @@ #include "test_suite.h" -#include <utils/enum.h> #include <utils/utils.h> /******************************************************************************* @@ -121,41 +120,50 @@ END_TEST */ static struct { + bool found; int val; char *str; } enum_tests_cont[] = { - {CONT1, "CONT1"}, - {CONT2, "CONT2"}, - {CONT2, "CoNt2"}, - {CONT3, "CONT3"}, - {CONT4, "CONT4"}, - {CONT5, "CONT5"}, - {-1, "asdf"}, - {-1, ""}, - {-1, NULL}, + {TRUE, CONT1, "CONT1"}, + {TRUE, CONT2, "CONT2"}, + {TRUE, CONT2, "CoNt2"}, + {TRUE, CONT3, "CONT3"}, + {TRUE, CONT4, "CONT4"}, + {TRUE, CONT5, "CONT5"}, + {FALSE, 0, "asdf"}, + {FALSE, 0, ""}, + {FALSE, 0, NULL}, }, enum_tests_split[] = { - {SPLIT1, "SPLIT1"}, - {SPLIT1, "split1"}, - {SPLIT2, "SPLIT2"}, - {SPLIT2, "SpLiT2"}, - {SPLIT3, "SPLIT3"}, - {SPLIT4, "SPLIT4"}, - {SPLIT5, "SPLIT5"}, - {-1, "asdf"}, - {-1, ""}, - {-1, NULL}, + {TRUE, SPLIT1, "SPLIT1"}, + {TRUE, SPLIT1, "split1"}, + {TRUE, SPLIT2, "SPLIT2"}, + {TRUE, SPLIT2, "SpLiT2"}, + {TRUE, SPLIT3, "SPLIT3"}, + {TRUE, SPLIT4, "SPLIT4"}, + {TRUE, SPLIT5, "SPLIT5"}, + {FALSE, 0, "asdf"}, + {FALSE, 0, ""}, + {FALSE, 0, NULL}, }; START_TEST(test_enum_from_name_cont) { - int val = enum_from_name(test_enum_cont_names, enum_tests_cont[_i].str); + int val = 0; + bool found; + + found = enum_from_name(test_enum_cont_names, enum_tests_cont[_i].str, &val); + ck_assert(enum_tests_cont[_i].found == found); ck_assert_int_eq(val, enum_tests_cont[_i].val); } END_TEST START_TEST(test_enum_from_name_split) { - int val = enum_from_name(test_enum_split_names, enum_tests_split[_i].str); + int val = 0; + bool found; + + found = enum_from_name(test_enum_split_names, enum_tests_split[_i].str, &val); + ck_assert(enum_tests_split[_i].found == found); ck_assert_int_eq(val, enum_tests_split[_i].val); } END_TEST diff --git a/src/libstrongswan/tests/suites/test_fetch_http.c b/src/libstrongswan/tests/suites/test_fetch_http.c index 8749ff375..9f1eef2f3 100644 --- a/src/libstrongswan/tests/suites/test_fetch_http.c +++ b/src/libstrongswan/tests/suites/test_fetch_http.c @@ -18,6 +18,8 @@ #include <unistd.h> #include <time.h> +#define HTTP_SUCCESS(status) ((status) >= 200 && (status) < 300) + /** * HTTP test definition */ @@ -42,6 +44,8 @@ typedef struct { void *res; /* length of response data */ int res_len; + /* status code, defaults to 200 */ + u_int code; } test_service_t; static char large[] = { @@ -147,40 +151,50 @@ static bool servicing(void *data, stream_t *stream) ck_assert(memeq(body, test->req, test->req_len)); } + if (!test->code) + { + test->code = 200; + } + /* response headers */ - snprintf(buf, sizeof(buf), "HTTP/1.%u 200 OK\r\n", test->minor); + snprintf(buf, sizeof(buf), "HTTP/1.%u %u OK\r\n", test->minor, test->code); ck_assert(stream->write_all(stream, buf, strlen(buf))); + + /* if the response code indicates an error the following write operations + * might fail because the client already terminated the TCP connection */ +#define may_fail(test, op) ck_assert(op || !HTTP_SUCCESS(test->code)) + t = time(NULL); gmtime_r(&t, &tm); strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z", &tm); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); snprintf(buf, sizeof(buf), "Server: strongSwan unit test\r\n"); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); /* rest of response headers */ snprintf(buf, sizeof(buf), "Content-Type: text/plain\r\n"); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); snprintf(buf, sizeof(buf), "Content-Length: %u\r\n", test->res_len); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); snprintf(buf, sizeof(buf), "Connection: close\r\n"); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); snprintf(buf, sizeof(buf), "\r\n"); - ck_assert(stream->write_all(stream, buf, strlen(buf))); + may_fail(test, stream->write_all(stream, buf, strlen(buf))); /* response body */ - ck_assert(stream->write_all(stream, test->res, test->res_len)); + may_fail(test, stream->write_all(stream, test->res, test->res_len)); return FALSE; } static test_service_t gtests[] = { { "GET", 1, "127.0.0.1", 6543, "/a/test/?b=c", NULL, - NULL, 0, "\x12\x34", 2 }, + NULL, 0, "\x12\x34", 2, 0 }, { "GET", 0, "localhost", 6543, "/", NULL, - NULL, 0, NULL, 0 }, + NULL, 0, NULL, 0, 0 }, { "GET", 0, "127.0.0.1", 6543, "/largefile", NULL, - NULL, 0, large, sizeof(large) }, + NULL, 0, large, sizeof(large), 0 }, { "GET", 1, "[::1]", 6543, "/ipv6-url", NULL, - NULL, 0, "\x00\r\n\r\x00testdatablabla", 20 }, + NULL, 0, "\x00\r\n\r\x00testdatablabla", 20, 0 }, }; START_TEST(test_get) @@ -215,11 +229,11 @@ END_TEST static test_service_t ptests[] = { { "POST", 1, "127.0.0.1", 6543, "/a/test/?b=c", "application/binary", - "\x23\x45", 2, "\x12\x34", 2 }, + "\x23\x45", 2, "\x12\x34", 2, 0 }, { "POST", 0, "localhost", 6543, "/largefile", "application/x-large", - large, sizeof(large), large, sizeof(large) }, + large, sizeof(large), large, sizeof(large), 0 }, { "POST", 1, "[::1]", 6543, "/ipv6-url", "text/plain", - "\x00\r\n\r\x00testdatablabla", 20, "\x00\r\n\r\x00testdatablabla", 20 }, + "\x00\r\n\r\x00testdatablabla", 20, "\x00\r\n\r\x00testdatablabla", 20, 0 }, }; START_TEST(test_post) @@ -254,6 +268,42 @@ START_TEST(test_post) } END_TEST + +static test_service_t rtests[] = { + { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 200 }, + { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 204 }, + { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 400 }, + { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 404 }, + { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 500 }, +}; + +START_TEST(test_response_code) +{ + stream_service_t *service; + status_t status; + chunk_t data = chunk_empty; + char uri[256]; + u_int code; + + lib->processor->set_threads(lib->processor, 8); + + snprintf(uri, sizeof(uri), "tcp://%s:%u", rtests[_i].host, rtests[_i].port); + service = lib->streams->create_service(lib->streams, uri, 1); + ck_assert(service != NULL); + service->on_accept(service, servicing, &rtests[_i], JOB_PRIO_HIGH, 0); + + snprintf(uri, sizeof(uri), "http://%s:%u%s", + rtests[_i].host, rtests[_i].port, rtests[_i].path); + status = lib->fetcher->fetch(lib->fetcher, uri, &data, + FETCH_RESPONSE_CODE, &code, FETCH_END); + ck_assert_int_eq(status, HTTP_SUCCESS(rtests[_i].code) ? SUCCESS : FAILED); + ck_assert_int_eq(code, rtests[_i].code); + free(data.ptr); + + service->destroy(service); +} +END_TEST + Suite *fetch_http_suite_create() { Suite *s; @@ -269,5 +319,9 @@ Suite *fetch_http_suite_create() tcase_add_loop_test(tc, test_post, 0, countof(ptests)); suite_add_tcase(s, tc); + tc = tcase_create("response code"); + tcase_add_loop_test(tc, test_response_code, 0, countof(rtests)); + suite_add_tcase(s, tc); + return s; } diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c index 30b9eb940..63442083a 100644 --- a/src/libstrongswan/tests/suites/test_host.c +++ b/src/libstrongswan/tests/suites/test_host.c @@ -286,8 +286,8 @@ END_TEST START_TEST(test_create_from_sockaddr_other) { - struct sockaddr_un addr = { - .sun_family = AF_UNIX, + struct sockaddr addr = { + .sa_family = AF_UNIX, }; host_t *host; diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c index edf53f0fd..5de785710 100644 --- a/src/libstrongswan/tests/suites/test_identification.c +++ b/src/libstrongswan/tests/suites/test_identification.c @@ -376,14 +376,14 @@ START_TEST(test_equals) "C=CH, E=moon@strongswan.org, CN=moon"); ck_assert(id_equals(a, "C=CH, E=moon@strongswan.org, CN=moon")); - ck_assert(id_equals(a, "C==CH, E==moon@strongswan.org,,, CN==moon")); + ck_assert(id_equals(a, "C==CH , E==moon@strongswan.org , CN==moon")); ck_assert(id_equals(a, " C=CH, E=moon@strongswan.org, CN=moon ")); ck_assert(id_equals(a, "C=ch, E=moon@STRONGSWAN.ORG, CN=Moon")); ck_assert(id_equals(a, "/C=CH/E=moon@strongswan.org/CN=moon")); - ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org/CN=moon")); - ck_assert(id_equals(a, "C=CH/E=moon@strongswan.org,CN=moon")); - ck_assert(id_equals(a, "C=CH / E=moon@strongswan.org , CN=moon")); + ck_assert(id_equals(a, " / C=CH / E=moon@strongswan.org / CN=moon")); + ck_assert(!id_equals(a, "C=CH/E=moon@strongswan.org/CN=moon")); + ck_assert(!id_equals(a, "C=CH/E=moon@strongswan.org,CN=moon")); ck_assert(!id_equals(a, "C=CH E=moon@strongswan.org CN=moon")); ck_assert(!id_equals(a, "C=CN, E=moon@strongswan.org, CN=moon")); ck_assert(!id_equals(a, "E=moon@strongswan.org, C=CH, CN=moon")); diff --git a/src/libstrongswan/tests/suites/test_settings.c b/src/libstrongswan/tests/suites/test_settings.c index 096465191..b9d429a24 100644 --- a/src/libstrongswan/tests/suites/test_settings.c +++ b/src/libstrongswan/tests/suites/test_settings.c @@ -17,12 +17,16 @@ #include <unistd.h> -#include <utils/settings.h> +#include <settings/settings.h> #include <utils/chunk.h> #include <utils/utils.h> #include <collections/linked_list.h> +#ifdef WIN32 +static char *path = "C:\\Windows\\Temp\\strongswan-settings-test"; +#else static char *path = "/tmp/strongswan-settings-test"; +#endif static settings_t *settings; static void create_settings(chunk_t contents) @@ -39,6 +43,7 @@ START_SETUP(setup_base_config) " # this gets overridden below\n" " key2 = val2\n" " none = \n" + " empty = \"\"\n" " sub1 {\n" " key = value\n" " key2 = value2\n" @@ -51,7 +56,8 @@ START_SETUP(setup_base_config) " sub% {\n" " id = %any\n" " }\n" - " key2 = with spaces\n" + " key2 = with space\n" + " key3 = \"string with\\nnewline\"\n" "}\n" "out = side\n" "other {\n" @@ -79,7 +85,9 @@ START_TEST(test_get_str) verify_string("val1", "main.key1"); verify_string("val1", "main..key1"); verify_string("val1", ".main.key1"); - verify_string("with spaces", "main.key2"); + verify_string("", "main.empty"); + verify_string("with space", "main.key2"); + verify_string("string with\nnewline", "main.key3"); verify_string("value", "main.sub1.key"); verify_string("value2", "main.sub1.key2"); verify_string("bar", "main.sub1.subsub.foo"); @@ -88,10 +96,8 @@ START_TEST(test_get_str) verify_string("side", "out"); verify_string("other val", "other.key1"); - /* FIXME: should this rather be undefined i.e. return the default value? */ - verify_string("", "main.none"); - - verify_null("main.key3"); + verify_null("main.none"); + verify_null("main.key4"); verify_null("other.sub"); } END_TEST @@ -125,16 +131,35 @@ START_TEST(test_get_str_printf) * probably document it at least */ verify_null("main.%s%u.key%d", "sub", 1, 2); - verify_null("%s.%s%d", "main", "key", 3); + verify_null("%s.%s%d", "main", "key", 4); } END_TEST START_TEST(test_set_str) { + char *val1, *val2; + + val1 = settings->get_str(settings, "main.key1", NULL); + ck_assert_str_eq("val1", val1); settings->set_str(settings, "main.key1", "val"); verify_string("val", "main.key1"); + /* the pointer we got before is still valid */ + ck_assert_str_eq("val1", val1); + + val2 = settings->get_str(settings, "main.key1", NULL); + ck_assert_str_eq("val", val2); settings->set_str(settings, "main.key1", "longer value"); verify_string("longer value", "main.key1"); + /* the pointers we got before are still valid */ + ck_assert_str_eq("val1", val1); + ck_assert_str_eq("val", val2); + + val1 = settings->get_str(settings, "main.key1", NULL); + settings->set_str(settings, "main.key1", "longer value"); + val2 = settings->get_str(settings, "main.key1", NULL); + /* setting the same string should should get us the same pointer */ + ck_assert(val1 == val2); + settings->set_str(settings, "main", "main val"); verify_string("main val", "main"); settings->set_str(settings, "main.sub1.new", "added"); @@ -183,6 +208,7 @@ START_SETUP(setup_bool_config) " key7 = disabled\n" " key8 = 0\n" " key9 = 5\n" + " empty = \"\"\n" " none = \n" " foo = bar\n" "}")); @@ -203,6 +229,8 @@ START_TEST(test_get_bool) verify_bool(FALSE, TRUE, "main.key7"); verify_bool(FALSE, TRUE, "main.key8"); + verify_bool(FALSE, FALSE, "main.empty"); + verify_bool(TRUE, TRUE, "main.empty"); verify_bool(FALSE, FALSE, "main.none"); verify_bool(TRUE, TRUE, "main.none"); verify_bool(FALSE, FALSE, "main.foo"); @@ -237,9 +265,9 @@ START_SETUP(setup_int_config) create_settings(chunk_from_str( "main {\n" " key1 = 5\n" - " # gets cut off\n" " key2 = 5.5\n" " key3 = -42\n" + " empty = \"\"\n" " none = \n" " foo1 = bar\n" " foo2 = bar13\n" @@ -254,14 +282,14 @@ END_SETUP START_TEST(test_get_int) { verify_int(5, 0, "main.key1"); - verify_int(5, 0, "main.key2"); + verify_int(0, 0, "main.key2"); verify_int(-42, 0, "main.key3"); - /* FIXME: do we want this behavior? */ - verify_int(0, 11, "main.none"); - verify_int(0, 11, "main.foo1"); - verify_int(0, 11, "main.foo2"); - verify_int(13, 11, "main.foo3"); + verify_int(11, 11, "main.empty"); + verify_int(11, 11, "main.none"); + verify_int(11, 11, "main.foo1"); + verify_int(11, 11, "main.foo2"); + verify_int(11, 11, "main.foo3"); verify_int(13, 13, "main.key4"); verify_int(-13, -13, "main"); @@ -291,6 +319,7 @@ START_SETUP(setup_double_config) " key2 = 5.5\n" " key3 = -42\n" " key4 = -42.5\n" + " empty = \"\"\n" " none = \n" " foo1 = bar\n" " foo2 = bar13.5\n" @@ -309,11 +338,11 @@ START_TEST(test_get_double) verify_double(-42, 0, "main.key3"); verify_double(-42.5, 0, "main.key4"); - /* FIXME: do we want this behavior? */ - verify_double(0, 11.5, "main.none"); - verify_double(0, 11.5, "main.foo1"); - verify_double(0, 11.5, "main.foo2"); - verify_double(13.5, 11.5, "main.foo3"); + verify_double(11.5, 11.5, "main.empty"); + verify_double(11.5, 11.5, "main.none"); + verify_double(11.5, 11.5, "main.foo1"); + verify_double(11.5, 11.5, "main.foo2"); + verify_double(11.5, 11.5, "main.foo3"); verify_double(11.5, 11.5, "main.key5"); verify_double(-11.5, -11.5, "main"); @@ -341,10 +370,12 @@ START_SETUP(setup_time_config) { create_settings(chunk_from_str( "main {\n" + " key0 = 5\n" " key1 = 5s\n" " key2 = 5m\n" - " key3 = 5h\n" - " key4 = 5d\n" + " key3 = 5 h\n" + " key4 = 5\td\n" + " empty = \"\"\n" " none = \n" " foo1 = bar\n" " foo2 = bar13\n" @@ -358,16 +389,17 @@ END_SETUP START_TEST(test_get_time) { + verify_time(5, 0, "main.key0"); verify_time(5, 0, "main.key1"); verify_time(300, 0, "main.key2"); verify_time(18000, 0, "main.key3"); verify_time(432000, 0, "main.key4"); - /* FIXME: do we want this behavior? */ - verify_time(0, 11, "main.none"); - verify_time(0, 11, "main.foo1"); - verify_time(0, 11, "main.foo2"); - verify_time(13, 11, "main.foo3"); + verify_time(11, 11, "main.empty"); + verify_time(11, 11, "main.none"); + verify_time(11, 11, "main.foo1"); + verify_time(11, 11, "main.foo2"); + verify_time(11, 11, "main.foo3"); verify_time(11, 11, "main.key5"); verify_time(11, 11, "main"); @@ -387,37 +419,21 @@ START_TEST(test_set_time) } END_TEST -static bool verify_section(linked_list_t *verifier, char *section) -{ - enumerator_t *enumerator; - char *current; - bool result = FALSE; - - enumerator = verifier->create_enumerator(verifier); - while (enumerator->enumerate(enumerator, ¤t)) - { - if (streq(current, section)) - { - verifier->remove_at(verifier, enumerator); - result = TRUE; - break; - } - } - enumerator->destroy(enumerator); - return result; -} - static void verify_sections(linked_list_t *verifier, char *parent) { - enumerator_t *enumerator; - char *section; + enumerator_t *enumerator, *ver; + char *section, *current; enumerator = settings->create_section_enumerator(settings, parent); - while (enumerator->enumerate(enumerator, §ion)) + ver = verifier->create_enumerator(verifier); + while (enumerator->enumerate(enumerator, §ion) && + ver->enumerate(ver, ¤t)) { - ck_assert(verify_section(verifier, section)); + ck_assert_str_eq(section, current); + verifier->remove_at(verifier, ver); } enumerator->destroy(enumerator); + ver->destroy(ver); ck_assert_int_eq(0, verifier->get_count(verifier)); verifier->destroy(verifier); } @@ -429,8 +445,8 @@ START_TEST(test_section_enumerator) verifier = linked_list_create_with_items("sub1", "sub%", NULL); verify_sections(verifier, "main"); - settings->set_str(settings, "main.sub2.new", "added"); - verifier = linked_list_create_with_items("sub1", "sub%", "sub2", NULL); + settings->set_str(settings, "main.sub0.new", "added"); + verifier = linked_list_create_with_items("sub1", "sub%", "sub0", NULL); verify_sections(verifier, "main"); verifier = linked_list_create_with_items("subsub", NULL); @@ -447,44 +463,27 @@ START_TEST(test_section_enumerator) } END_TEST -static bool verify_key_value(linked_list_t *keys, linked_list_t *values, - char *key, char *value) +static void verify_key_values(linked_list_t *keys, linked_list_t *values, + char *parent) { - enumerator_t *enum_keys, *enum_values; - char *current_key, *current_value; - bool result = FALSE; + enumerator_t *enumerator, *enum_keys, *enum_values; + char *key, *value, *current_key, *current_value; + enumerator = settings->create_key_value_enumerator(settings, parent); enum_keys = keys->create_enumerator(keys); enum_values = values->create_enumerator(values); - while (enum_keys->enumerate(enum_keys, ¤t_key) && + while (enumerator->enumerate(enumerator, &key, &value) && + enum_keys->enumerate(enum_keys, ¤t_key) && enum_values->enumerate(enum_values, ¤t_value)) { - if (streq(current_key, key)) - { - ck_assert_str_eq(current_value, value); - keys->remove_at(keys, enum_keys); - values->remove_at(values, enum_values); - result = TRUE; - break; - } + ck_assert_str_eq(current_key, key); + ck_assert_str_eq(current_value, value); + keys->remove_at(keys, enum_keys); + values->remove_at(values, enum_values); } + enumerator->destroy(enumerator); enum_keys->destroy(enum_keys); enum_values->destroy(enum_values); - return result; -} - -static void verify_key_values(linked_list_t *keys, linked_list_t *values, - char *parent) -{ - enumerator_t *enumerator; - char *key, *value; - - enumerator = settings->create_key_value_enumerator(settings, parent); - while (enumerator->enumerate(enumerator, &key, &value)) - { - ck_assert(verify_key_value(keys, values, key, value)); - } - enumerator->destroy(enumerator); ck_assert_int_eq(0, keys->get_count(keys)); keys->destroy(keys); values->destroy(values); @@ -494,8 +493,8 @@ START_TEST(test_key_value_enumerator) { linked_list_t *keys, *values; - keys = linked_list_create_with_items("key1", "key2", "none", NULL); - values = linked_list_create_with_items("val1", "with spaces", "", NULL); + keys = linked_list_create_with_items("key1", "key2", "empty", "key3", NULL); + values = linked_list_create_with_items("val1", "with space", "", "string with\nnewline", NULL); verify_key_values(keys, values, "main"); keys = linked_list_create_with_items("key", "key2", "subsub", NULL); @@ -522,8 +521,13 @@ START_TEST(test_key_value_enumerator) } END_TEST -#define include1 "/tmp/strongswan-settings-test-include1" -#define include2 "/tmp/strongswan-settings-test-include2" +#ifdef WIN32 +# define include1 "C:\\Windows\\Temp\\strongswan-settings-test-include1" +# define include2 "C:\\Windows\\Temp\\strongswan-settings-test-include2" +#else +# define include1 "/tmp/strongswan-settings-test-include1" +# define include2 "/tmp/strongswan-settings-test-include2" +#endif START_SETUP(setup_include_config) { @@ -531,6 +535,7 @@ START_SETUP(setup_include_config) "main {\n" " key1 = n1\n" " key2 = n2\n" + " key3 = val3\n" " none = \n" " sub1 {\n" " key3 = value\n" @@ -563,13 +568,15 @@ static void verify_include() { verify_string("n1", "main.key1"); verify_string("v2", "main.key2"); - verify_string("", "main.none"); + verify_string("val3", "main.key3"); verify_string("val", "main.sub1.key"); verify_string("v2", "main.sub1.key2"); verify_string("val", "main.sub1.sub1.key"); verify_string("value", "main.sub1.key3"); verify_string("value", "main.sub1.include"); verify_string("val3", "main.sub2.sub3"); + + verify_null("main.none"); } START_TEST(test_include) @@ -580,13 +587,13 @@ START_TEST(test_include) " key2 = val2\n" " none = x\n" " sub1 {\n" + " include this/does/not/exist.conf\n" " include = value\n" " key2 = value2\n" " include " include2 "\n" " }\n" "}\n" - "# currently there must be a newline after include statements\n" - "include " include1 "\n"); + "include " include1); create_settings(contents); verify_include(); @@ -599,6 +606,7 @@ START_TEST(test_load_files) "main {\n" " key1 = val1\n" " key2 = val2\n" + " key3 = val3\n" " none = x\n" " sub1 {\n" " include = value\n" @@ -608,7 +616,33 @@ START_TEST(test_load_files) " }\n" " }\n" "}"); + char *val1, *val2, *val3; + + create_settings(contents); + + val1 = settings->get_str(settings, "main.key1", NULL); + val2 = settings->get_str(settings, "main.sub1.key2", NULL); + /* loading the same file twice should not change anything, with... */ + ck_assert(settings->load_files(settings, path, TRUE)); + ck_assert(val1 == settings->get_str(settings, "main.key1", NULL)); + ck_assert(val2 == settings->get_str(settings, "main.sub1.key2", NULL)); + /* ...or without merging */ + ck_assert(settings->load_files(settings, path, FALSE)); + ck_assert(val1 == settings->get_str(settings, "main.key1", NULL)); + ck_assert(val2 == settings->get_str(settings, "main.sub1.key2", NULL)); + + val1 = settings->get_str(settings, "main.key2", NULL); + val2 = settings->get_str(settings, "main.key3", NULL); + val3 = settings->get_str(settings, "main.none", NULL); + /* only pointers for modified settings should change, but still be valid */ + ck_assert(settings->load_files(settings, include1, FALSE)); + ck_assert(val1 != settings->get_str(settings, "main.key2", NULL)); + ck_assert_str_eq(val1, "val2"); + ck_assert(val2 == settings->get_str(settings, "main.key3", NULL)); + ck_assert(val3 != settings->get_str(settings, "main.none", NULL)); + ck_assert_str_eq(val3, "x"); + settings->destroy(settings); create_settings(contents); ck_assert(settings->load_files(settings, include1, TRUE)); @@ -641,15 +675,20 @@ START_TEST(test_load_files_section) ck_assert(settings->load_files_section(settings, include2, TRUE, "main.sub1")); verify_include(); - /* non existing files are no failure */ - ck_assert(settings->load_files_section(settings, include1".conf", TRUE, "")); + /* non existing files are a failure here */ + ck_assert(!settings->load_files_section(settings, include1".conf", TRUE, "")); verify_include(); - /* unreadable files are */ - ck_assert(chunk_write(contents, include1".no", 0444, TRUE)); - ck_assert(!settings->load_files_section(settings, include1".no", TRUE, "")); - unlink(include1".no"); - verify_include(); +#ifndef WIN32 + /* unreadable files are too (only fails when not running as root) */ + if (getuid() != 0) + { + ck_assert(chunk_write(contents, include1".no", 0444, TRUE)); + ck_assert(!settings->load_files_section(settings, include1".no", TRUE, "")); + unlink(include1".no"); + verify_include(); + } +#endif ck_assert(settings->load_files_section(settings, include2, FALSE, "main")); verify_null("main.key1"); @@ -664,6 +703,87 @@ START_TEST(test_load_files_section) } END_TEST +START_TEST(test_order_kv) +{ + chunk_t base = chunk_from_str( + "main {\n" + " key1 = val1\n" + " key2 = val2\n" + " key3 = val3\n" + "}"); + chunk_t include = chunk_from_str( + "main {\n" + " key0 = val0\n" + " key3 = val3\n" + " key1 = val1\n" + "}"); + linked_list_t *keys, *values; + + create_settings(base); + ck_assert(chunk_write(include, include1, 0022, TRUE)); + + keys = linked_list_create_with_items("key1", "key2", "key3", NULL); + values = linked_list_create_with_items("val1", "val2", "val3", NULL); + verify_key_values(keys, values, "main"); + + /* the original order is maintained if the settings are merged */ + ck_assert(settings->load_files(settings, include1, TRUE)); + keys = linked_list_create_with_items("key1", "key2", "key3", "key0", NULL); + values = linked_list_create_with_items("val1", "val2", "val3", "val0", NULL); + verify_key_values(keys, values, "main"); + + /* but the new order is adopted if the settings are replaced */ + ck_assert(settings->load_files(settings, include1, FALSE)); + keys = linked_list_create_with_items("key0", "key3", "key1", NULL); + values = linked_list_create_with_items("val0", "val3", "val1", NULL); + verify_key_values(keys, values, "main"); + + unlink(include1); +} +END_TEST + +START_TEST(test_order_section) +{ + chunk_t base = chunk_from_str( + "main {\n" + " sub1 {\n" + " }\n" + " sub2 {\n" + " }\n" + " sub3 {\n" + " }\n" + "}"); + chunk_t include = chunk_from_str( + "main {\n" + " sub0 {\n" + " }\n" + " sub3 {\n" + " }\n" + " sub1 {\n" + " }\n" + "}"); + linked_list_t *sections; + + create_settings(base); + ck_assert(chunk_write(include, include1, 0022, TRUE)); + + sections = linked_list_create_with_items("sub1", "sub2", "sub3", NULL); + verify_sections(sections, "main"); + + /* the original order is maintained if the settings are merged */ + ck_assert(settings->load_files(settings, include1, TRUE)); + sections = linked_list_create_with_items("sub1", "sub2", "sub3", "sub0", NULL); + verify_sections(sections, "main"); + + /* but the new order is adopted if the settings are replaced */ + ck_assert(settings->load_files(settings, include1, FALSE)); + sections = linked_list_create_with_items("sub0", "sub3", "sub1", NULL); + verify_sections(sections, "main"); + + unlink(include1); +} +END_TEST + START_SETUP(setup_fallback_config) { create_settings(chunk_from_str( @@ -781,57 +901,85 @@ START_TEST(test_add_fallback_printf) } END_TEST -START_SETUP(setup_invalid_config) +START_SETUP(setup_string_config) { create_settings(chunk_from_str( - "# section without name\n" - "{\n" - " key1 = val1\n" - "}\n" - "main {\n" - " key2 = val2\n" - " # value without key\n" - " = val3\n" - " key4 = val4\n" - " # key without value does not change it\n" - " key4\n" - " # subsection without name\n" - " {\n" - " key5 = val5\n" - " }\n" - " # empty include pattern\n" - " include\n" - " key6 = val6\n" - "}")); + "string = \" with accurate\twhitespace\"\n" + "special = \"all { special } characters # can be used.\"\n" + "unterminated = \"is fine\n" + "but = produces a warning\n" + "newlines = \"can either be encoded\\nor\\\n" + "escaped\"\n" + "quotes = \"\\\"and\\\" slashes \\\\ can \\\\ be\" # escaped too\n" + "multiple = \"strings\" are \"combined\"\n" + )); } END_SETUP -START_TEST(test_invalid) +START_TEST(test_strings) +{ + verify_string(" with accurate\twhitespace", "string"); + verify_string("all { special } characters # can be used.", "special"); + verify_string("is fine", "unterminated"); + verify_string("produces a warning", "but"); + verify_string("can either be encoded\nor\nescaped", "newlines"); + verify_string("\"and\" slashes \\ can \\ be", "quotes"); + verify_string("strings are combined", "multiple"); +} +END_TEST + +START_TEST(test_valid) { - linked_list_t *keys, *values; chunk_t contents; - verify_null("key1"); - verify_null(".key1"); - verify_null("%s.key1", ""); - verify_string("val2", "main.key2"); - verify_string("val4", "main.key4"); - verify_null("main..key5"); - verify_string("val6", "main.key6"); + contents = chunk_from_str( + "single = value"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(settings->load_files(settings, path, FALSE)); + verify_string("value", "single"); - keys = linked_list_create_with_items("main", NULL); - verify_sections(keys, ""); + contents = chunk_from_str( + "singleline { single = value }"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(settings->load_files(settings, path, FALSE)); + verify_string("value", "singleline.single"); - keys = linked_list_create_with_items(NULL); - verify_sections(keys, "main"); + contents = chunk_from_str( + "singleline { sub { sub1 = val1 } single = value }"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(settings->load_files(settings, path, FALSE)); + verify_string("val1", "singleline.sub.sub1"); - keys = linked_list_create_with_items("key2", "key4", "key6", NULL); - values = linked_list_create_with_items("val2", "val4", "val6", NULL); - verify_key_values(keys, values, "main"); + contents = chunk_from_str( + "newline\n { single = value }"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(settings->load_files(settings, path, FALSE)); + verify_string("value", "newline.single"); + + contents = chunk_from_str( + "section {\n" + " include # without pattern produces a warning, but is fine\n" + "}\n"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(settings->load_files(settings, path, FALSE)); +} +END_TEST + +START_TEST(test_invalid) +{ + chunk_t contents; + + contents = chunk_from_str( + "{\n" + " no = section name\n" + "}\n"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(!settings->load_files(settings, path, FALSE)); - /* FIXME: we should probably fix this */ contents = chunk_from_str( - "requires = newline"); + "no {\n" + " = key name\n" + "}\n"); ck_assert(chunk_write(contents, path, 0022, TRUE)); ck_assert(!settings->load_files(settings, path, FALSE)); @@ -842,7 +990,12 @@ START_TEST(test_invalid) ck_assert(!settings->load_files(settings, path, FALSE)); contents = chunk_from_str( - "singleline { not = valid }\n"); + "spaces in name {}"); + ck_assert(chunk_write(contents, path, 0022, TRUE)); + ck_assert(!settings->load_files(settings, path, FALSE)); + + contents = chunk_from_str( + "only = a single setting = per line"); ck_assert(chunk_write(contents, path, 0022, TRUE)); ck_assert(!settings->load_files(settings, path, FALSE)); } @@ -903,6 +1056,8 @@ Suite *settings_suite_create() tcase_add_test(tc, test_include); tcase_add_test(tc, test_load_files); tcase_add_test(tc, test_load_files_section); + tcase_add_test(tc, test_order_kv); + tcase_add_test(tc, test_order_section); suite_add_tcase(s, tc); tc = tcase_create("fallback"); @@ -911,8 +1066,14 @@ Suite *settings_suite_create() tcase_add_test(tc, test_add_fallback_printf); suite_add_tcase(s, tc); - tc = tcase_create("invalid data"); - tcase_add_checked_fixture(tc, setup_invalid_config, teardown_config); + tc = tcase_create("strings"); + tcase_add_checked_fixture(tc, setup_string_config, teardown_config); + tcase_add_test(tc, test_strings); + suite_add_tcase(s, tc); + + tc = tcase_create("valid/invalid data"); + tcase_add_checked_fixture(tc, setup_base_config, teardown_config); + tcase_add_test(tc, test_valid); tcase_add_test(tc, test_invalid); suite_add_tcase(s, tc); diff --git a/src/libstrongswan/tests/suites/test_stream.c b/src/libstrongswan/tests/suites/test_stream.c index 2d3173d46..899306af2 100644 --- a/src/libstrongswan/tests/suites/test_stream.c +++ b/src/libstrongswan/tests/suites/test_stream.c @@ -18,7 +18,9 @@ #include <unistd.h> static char* services[] = { +#ifndef WIN32 "unix:///tmp/strongswan-test-service.sck", +#endif "tcp://127.0.0.1:7766", "tcp://[::1]:7766", }; @@ -121,7 +123,6 @@ START_TEST(test_async) stream_service_t *service; stream_t *stream; - lib->processor->set_threads(lib->processor, 8); service = lib->streams->create_service(lib->streams, services[_i], 1); diff --git a/src/libstrongswan/tests/suites/test_threading.c b/src/libstrongswan/tests/suites/test_threading.c index 844959e46..0526d9d6e 100644 --- a/src/libstrongswan/tests/suites/test_threading.c +++ b/src/libstrongswan/tests/suites/test_threading.c @@ -16,7 +16,6 @@ #include "test_suite.h" -#include <sched.h> #include <unistd.h> #include <threading/thread.h> @@ -1215,6 +1214,8 @@ static void *cleanup_cancel_run(void *data) { thread_cancelability(FALSE); + barrier_wait(barrier); + thread_cleanup_push(cleanup3, data); thread_cleanup_push(cleanup2, data); thread_cleanup_push(cleanup1, data); @@ -1234,11 +1235,13 @@ START_TEST(test_cleanup_cancel) uintptr_t values[THREADS]; int i; + barrier = barrier_create(THREADS+1); for (i = 0; i < THREADS; i++) { values[i] = 1; threads[i] = thread_create(cleanup_cancel_run, &values[i]); } + barrier_wait(barrier); for (i = 0; i < THREADS; i++) { threads[i]->cancel(threads[i]); @@ -1248,6 +1251,7 @@ START_TEST(test_cleanup_cancel) threads[i]->join(threads[i]); ck_assert_int_eq(values[i], 4); } + barrier_destroy(barrier); } END_TEST diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 0260726b2..abca4620e 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -508,34 +508,55 @@ START_TEST(test_strreplace) END_TEST /******************************************************************************* - * path_dirname/basename + * path_dirname/basename/absolute */ static struct { char *path; char *dir; char *base; + bool absolute; } path_data[] = { - {NULL, ".", "."}, - {"", ".", "."}, - {".", ".", "."}, - {"..", ".", ".."}, - {"/", "/", "/"}, - {"//", "/", "/"}, - {"foo", ".", "foo"}, - {"f/", ".", "f"}, - {"foo/", ".", "foo"}, - {"foo//", ".", "foo"}, - {"/f", "/", "f"}, - {"/f/", "/", "f"}, - {"/foo", "/", "foo"}, - {"/foo/", "/", "foo"}, - {"//foo/", "/", "foo"}, - {"foo/bar", "foo", "bar"}, - {"foo//bar", "foo", "bar"}, - {"/foo/bar", "/foo", "bar"}, - {"/foo/bar/", "/foo", "bar"}, - {"/foo/bar/baz", "/foo/bar", "baz"}, + {NULL, ".", ".", FALSE}, + {"", ".", ".", FALSE}, + {".", ".", ".", FALSE}, + {"..", ".", "..", FALSE}, +#ifdef WIN32 + {"C:\\", "C:", "C:", TRUE}, + {"X:\\\\", "X:", "X:", TRUE}, + {"foo", ".", "foo", FALSE}, + {"f\\", ".", "f", FALSE}, + {"foo\\", ".", "foo", FALSE}, + {"foo\\\\", ".", "foo", FALSE}, + {"d:\\f", "d:", "f", TRUE}, + {"C:\\f\\", "C:", "f", TRUE}, + {"C:\\foo", "C:", "foo", TRUE}, + {"C:\\foo\\", "C:", "foo", TRUE}, + {"foo\\bar", "foo", "bar", FALSE}, + {"foo\\\\bar", "foo", "bar", FALSE}, + {"C:\\foo\\bar", "C:\\foo", "bar", TRUE}, + {"C:\\foo\\bar\\", "C:\\foo", "bar", TRUE}, + {"C:\\foo\\bar\\baz", "C:\\foo\\bar", "baz", TRUE}, + {"\\foo\\bar", "\\foo", "bar", FALSE}, + {"\\\\foo\\bar", "\\\\foo", "bar", TRUE}, +#else /* !WIN32 */ + {"/", "/", "/", TRUE}, + {"//", "/", "/", TRUE}, + {"foo", ".", "foo", FALSE}, + {"f/", ".", "f", FALSE}, + {"foo/", ".", "foo", FALSE}, + {"foo//", ".", "foo", FALSE}, + {"/f", "/", "f", TRUE}, + {"/f/", "/", "f", TRUE}, + {"/foo", "/", "foo", TRUE}, + {"/foo/", "/", "foo", TRUE}, + {"//foo/", "/", "foo", TRUE}, + {"foo/bar", "foo", "bar", FALSE}, + {"foo//bar", "foo", "bar", FALSE}, + {"/foo/bar", "/foo", "bar", TRUE}, + {"/foo/bar/", "/foo", "bar", TRUE}, + {"/foo/bar/baz", "/foo/bar", "baz", TRUE}, +#endif }; START_TEST(test_path_dirname) @@ -558,6 +579,12 @@ START_TEST(test_path_basename) } END_TEST +START_TEST(test_path_absolute) +{ + ck_assert(path_data[_i].absolute == path_absolute(path_data[_i].path)); +} +END_TEST + /******************************************************************************* * time_printf_hook */ @@ -674,7 +701,11 @@ Suite *utils_suite_create() TCase *tc; /* force a timezone to match non-UTC conversions */ +#ifdef WIN32 + _putenv("TZ=GST-1GDT"); +#else setenv("TZ", "Europe/Zurich", 1); +#endif tzset(); s = suite_create("utils"); @@ -725,11 +756,18 @@ Suite *utils_suite_create() tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data)); suite_add_tcase(s, tc); - tc = tcase_create("path_dirname/basename"); + tc = tcase_create("path_dirname"); tcase_add_loop_test(tc, test_path_dirname, 0, countof(path_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("path_basename"); tcase_add_loop_test(tc, test_path_basename, 0, countof(path_data)); suite_add_tcase(s, tc); + tc = tcase_create("path_absolute"); + tcase_add_loop_test(tc, test_path_absolute, 0, countof(path_data)); + suite_add_tcase(s, tc); + tc = tcase_create("printf_hooks"); tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data)); tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data)); diff --git a/src/libstrongswan/tests/suites/test_watcher.c b/src/libstrongswan/tests/suites/test_watcher.c index 9415bead9..11b4c3a7d 100644 --- a/src/libstrongswan/tests/suites/test_watcher.c +++ b/src/libstrongswan/tests/suites/test_watcher.c @@ -17,7 +17,6 @@ #include <library.h> -#include <sched.h> #include <unistd.h> #include <errno.h> @@ -48,7 +47,7 @@ START_TEST(test_read) for (c = 'a'; c <= 'z'; c++) { - ck_assert_int_eq(write(fd[1], &c, 1), 1); + ck_assert_int_eq(send(fd[1], &c, 1, 0), 1); while (testbuf[0] != c) { sched_yield(); @@ -84,7 +83,7 @@ START_TEST(test_write) lib->watcher->add(lib->watcher, fd[1], WATCHER_WRITE, writecb, &in); - ck_assert_int_eq(read(fd[0], &out, 1), 1); + ck_assert_int_eq(recv(fd[0], &out, 1, 0), 1); ck_assert_int_eq(out, in); lib->watcher->remove(lib->watcher, fd[1]); @@ -123,7 +122,7 @@ START_TEST(test_multiread) { for (in = 'a'; in <= 'z'; in++) { - ck_assert_int_eq(write(fd[i][1], &in, 1), 1); + ck_assert_int_eq(send(fd[i][1], &in, 1, 0), 1); while (out[i] != in) { sched_yield(); @@ -171,7 +170,7 @@ START_TEST(test_multiwrite) { for (i = 0; i < countof(fd); i++) { - ck_assert_int_eq(read(fd[i][0], &out, 1), 1); + ck_assert_int_eq(recv(fd[i][0], &out, 1, 0), 1); ck_assert_int_eq(out, i); } } diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 5ec4198e7..8f2e9855e 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -18,6 +18,7 @@ #include "test_runner.h" #include <library.h> +#include <threading/thread.h> #include <plugins/plugin_feature.h> #include <collections/array.h> #include <utils/test.h> @@ -26,6 +27,7 @@ #include <dirent.h> #include <unistd.h> #include <limits.h> +#include <stdlib.h> /** * Get a tty color escape character for stderr @@ -33,32 +35,12 @@ #define TTY(color) tty_escape_get(2, TTY_FG_##color) /** - * Initialize the lookup table for testable functions (defined in - * libstrongswan). We don't use the constructor attribute as the order can't - * really be defined (clang does not support it and gcc does not adhere to it in - * the monolithic build). The function here is a weak symbol in libstrongswan. + * A global symbol indicating libtest linkage */ -void testable_functions_create() -{ - if (!testable_functions) - { - testable_functions = hashtable_create(hashtable_hash_str, - hashtable_equals_str, 8); - } -} - -/** - * Destroy the lookup table for testable functions - */ -static void testable_functions_destroy() __attribute__ ((destructor)); -static void testable_functions_destroy() -{ - DESTROY_IF(testable_functions); - /* if leak detective is enabled plugins are not actually unloaded, which - * means their destructor is called AFTER this one when the process - * terminates, make sure this does not crash */ - testable_functions = NULL; -} +#ifdef WIN32 +__declspec(dllexport) +#endif +bool test_runner_available = TRUE; /** * Destroy a single test suite and associated data @@ -114,13 +96,13 @@ static void filter_suites(array_t *loaded) * Load all available test suites, or optionally only selected ones. */ static array_t *load_suites(test_configuration_t configs[], - test_runner_init_t init) + test_runner_init_t init, char *cfg) { array_t *suites; bool old = FALSE; int i; - library_init(NULL, "test-runner"); + library_init(cfg, "test-runner"); test_setup_handler(); @@ -205,11 +187,17 @@ static bool call_fixture(test_case_t *tcase, bool up) { if (up) { - fixture->setup(); + if (fixture->setup) + { + fixture->setup(); + } } else { - fixture->teardown(); + if (fixture->teardown) + { + fixture->teardown(); + } } } else @@ -226,12 +214,12 @@ static bool call_fixture(test_case_t *tcase, bool up) /** * Test initialization, initializes libstrongswan for the next run */ -static bool pre_test(test_runner_init_t init) +static bool pre_test(test_runner_init_t init, char *cfg) { level_t level = LEVEL_SILENT; char *verbosity; - library_init(NULL, "test-runner"); + library_init(cfg, "test-runner"); /* use non-blocking RNG to generate keys fast */ lib->settings->set_default_str(lib->settings, @@ -371,6 +359,7 @@ static void print_failures(array_t *failures) { failure_t failure; + threads_init(); backtrace_init(); while (array_remove(failures, 0, &failure)) @@ -390,12 +379,13 @@ static void print_failures(array_t *failures) } backtrace_deinit(); + threads_deinit(); } /** * Run a single test case with fixtures */ -static bool run_case(test_case_t *tcase, test_runner_init_t init) +static bool run_case(test_case_t *tcase, test_runner_init_t init, char *cfg) { enumerator_t *enumerator; test_function_t *tfun; @@ -414,7 +404,7 @@ static bool run_case(test_case_t *tcase, test_runner_init_t init) for (i = tfun->start; i < tfun->end; i++) { - if (pre_test(init)) + if (pre_test(init, cfg)) { bool ok = FALSE; int leaks = 0; @@ -483,7 +473,7 @@ static bool run_case(test_case_t *tcase, test_runner_init_t init) /** * Run a single test suite */ -static bool run_suite(test_suite_t *suite, test_runner_init_t init) +static bool run_suite(test_suite_t *suite, test_runner_init_t init, char *cfg) { enumerator_t *enumerator; test_case_t *tcase; @@ -494,7 +484,7 @@ static bool run_suite(test_suite_t *suite, test_runner_init_t init) enumerator = array_create_enumerator(suite->tcases); while (enumerator->enumerate(enumerator, &tcase)) { - if (run_case(tcase, init)) + if (run_case(tcase, init, cfg)) { passed++; } @@ -522,11 +512,14 @@ int test_runner_run(const char *name, test_configuration_t configs[], test_suite_t *suite; enumerator_t *enumerator; int passed = 0, result; + char *cfg; /* redirect all output to stderr (to redirect make's stdout to /dev/null) */ dup2(2, 1); - suites = load_suites(configs, init); + cfg = getenv("TESTS_STRONGSWAN_CONF"); + + suites = load_suites(configs, init, cfg); if (!suites) { return EXIT_FAILURE; @@ -537,7 +530,7 @@ int test_runner_run(const char *name, test_configuration_t configs[], enumerator = array_create_enumerator(suites); while (enumerator->enumerate(enumerator, &suite)) { - if (run_suite(suite, init)) + if (run_suite(suite, init, cfg)) { passed++; } diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index 643b622e5..de87a1f0f 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -64,7 +64,13 @@ struct test_configuration_t { /** * Run test configuration. * - * The configs array must be terminated with a NULL element. + * The configs array must be terminated with a NULL element. The following + * environment variables are currently supported: + * + * - TESTS_VERBOSITY: Numerical loglevel for debug log + * - TESTS_STRONGSWAN_CONF: Specify a path to a custom strongswan.conf + * - TESTS_SUITES: Run specific test suites only + * - TESTS_REDUCED_KEYLENGTHS: Test minimal keylengths for public key tests only * * @param name name of test runner * @param config test suite constructors with dependencies diff --git a/src/libstrongswan/tests/test_suite.c b/src/libstrongswan/tests/test_suite.c index fb40b05c1..00ac31830 100644 --- a/src/libstrongswan/tests/test_suite.c +++ b/src/libstrongswan/tests/test_suite.c @@ -18,7 +18,11 @@ #include <signal.h> #include <unistd.h> +#ifndef WIN32 #include <pthread.h> +#endif + +#include <threading/thread.h> /** * Failure message buf @@ -41,9 +45,9 @@ static int failure_line; static backtrace_t *failure_backtrace; /** - * Longjump restore point when failing + * Flag to indicate if a worker thread failed */ -sigjmp_buf test_restore_point_env; +static bool worker_failed; /** * See header. @@ -119,54 +123,200 @@ void test_suite_add_case(test_suite_t *suite, test_case_t *tcase) array_insert(suite->tcases, -1, tcase); } +#ifdef WIN32 + /** - * Main thread performing tests + * Longjump restore point when failing */ -static pthread_t main_thread; +jmp_buf test_restore_point_env; + +/** + * Thread ID of main thread + */ +static DWORD main_thread; + +/** + * APC routine invoked by main thread on worker failure + */ +static void WINAPI set_worker_failure(ULONG_PTR dwParam) +{ + worker_failed = TRUE; +} /** * Let test case fail */ -static inline void test_failure() +static void test_failure() { - if (pthread_self() == main_thread) + if (GetCurrentThreadId() == main_thread) { - siglongjmp(test_restore_point_env, 1); + longjmp(test_restore_point_env, 1); } else { - pthread_kill(main_thread, SIGUSR1); - /* terminate thread to prevent it from going wild */ - pthread_exit(NULL); + HANDLE *thread; + + thread = OpenThread(THREAD_SET_CONTEXT, FALSE, main_thread); + if (thread) + { + QueueUserAPC(set_worker_failure, thread, (uintptr_t)NULL); + CloseHandle(thread); + } + thread_exit(NULL); } } /** * See header. */ -void test_fail_vmsg(const char *file, int line, char *fmt, va_list args) +void test_fail_if_worker_failed() { - vsnprintf(failure_buf, sizeof(failure_buf), fmt, args); - failure_line = line; - failure_file = file; + if (GetCurrentThreadId() == main_thread && worker_failed) + { + test_failure(); + } +} - test_failure(); +/** + * Vectored exception handler + */ +static long WINAPI eh_handler(PEXCEPTION_POINTERS ei) +{ + char *ename; + bool old = FALSE; + + switch (ei->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + ename = "ACCESS_VIOLATION"; + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + ename = "ARRAY_BOUNDS_EXCEEDED"; + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + ename = "DATATYPE_MISALIGNMENT"; + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + ename = "FLT_DENORMAL_OPERAND"; + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + ename = "FLT_DIVIDE_BY_ZERO"; + break; + case EXCEPTION_FLT_INEXACT_RESULT: + ename = "FLT_INEXACT_RESULT"; + break; + case EXCEPTION_FLT_INVALID_OPERATION: + ename = "FLT_INVALID_OPERATION"; + break; + case EXCEPTION_FLT_OVERFLOW: + ename = "FLT_OVERFLOW"; + break; + case EXCEPTION_FLT_STACK_CHECK: + ename = "FLT_STACK_CHECK"; + break; + case EXCEPTION_FLT_UNDERFLOW: + ename = "FLT_UNDERFLOW"; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + ename = "ILLEGAL_INSTRUCTION"; + break; + case EXCEPTION_IN_PAGE_ERROR: + ename = "IN_PAGE_ERROR"; + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + ename = "INT_DIVIDE_BY_ZERO"; + break; + case EXCEPTION_INT_OVERFLOW: + ename = "INT_OVERFLOW"; + break; + case EXCEPTION_INVALID_DISPOSITION: + ename = "INVALID_DISPOSITION"; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + ename = "NONCONTINUABLE_EXCEPTION"; + break; + case EXCEPTION_PRIV_INSTRUCTION: + ename = "PRIV_INSTRUCTION"; + break; + case EXCEPTION_STACK_OVERFLOW: + ename = "STACK_OVERFLOW"; + break; + default: + return EXCEPTION_CONTINUE_EXECUTION; + } + + if (lib->leak_detective) + { + old = lib->leak_detective->set_state(lib->leak_detective, FALSE); + } + failure_backtrace = backtrace_create(5); + if (lib->leak_detective) + { + lib->leak_detective->set_state(lib->leak_detective, old); + } + failure_line = 0; + test_fail_msg(NULL, 0, "%s exception", ename); + /* not reached */ + return EXCEPTION_CONTINUE_EXECUTION; } /** * See header. */ -void test_fail_msg(const char *file, int line, char *fmt, ...) +void test_setup_handler() { - va_list args; + main_thread = GetCurrentThreadId(); + AddVectoredExceptionHandler(0, eh_handler); +} - va_start(args, fmt); - vsnprintf(failure_buf, sizeof(failure_buf), fmt, args); - failure_line = line; - failure_file = file; - va_end(args); +/** + * See header. + */ +void test_setup_timeout(int s) +{ + /* TODO: currently not supported. SetTimer()? */ - test_failure(); + worker_failed = FALSE; +} + +#else /* !WIN32 */ + +/** + * Longjump restore point when failing + */ +sigjmp_buf test_restore_point_env; + +/** + * Main thread performing tests + */ +static pthread_t main_thread; + +/** + * Let test case fail + */ +static inline void test_failure() +{ + if (pthread_self() == main_thread) + { + siglongjmp(test_restore_point_env, 1); + } + else + { + pthread_kill(main_thread, SIGUSR1); + /* terminate thread to prevent it from going wild */ + pthread_exit(NULL); + } +} + +/** + * See header. + */ +void test_fail_if_worker_failed() +{ + if (pthread_self() == main_thread && worker_failed) + { + test_failure(); + } } /** @@ -180,8 +330,9 @@ static void test_sighandler(int signal) switch (signal) { case SIGUSR1: - /* a different thread failed, abort test */ - return test_failure(); + /* a different thread failed, abort test at the next opportunity */ + worker_failed = TRUE; + return; case SIGSEGV: signame = "SIGSEGV"; break; @@ -251,6 +402,37 @@ void test_setup_timeout(int s) sigaction(SIGUSR1, &action, NULL); alarm(s); + + worker_failed = FALSE; +} + +#endif /* !WIN32 */ + +/** + * See header. + */ +void test_fail_vmsg(const char *file, int line, char *fmt, va_list args) +{ + vsnprintf(failure_buf, sizeof(failure_buf), fmt, args); + failure_line = line; + failure_file = file; + + test_failure(); +} +/** + * See header. + */ +void test_fail_msg(const char *file, int line, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsnprintf(failure_buf, sizeof(failure_buf), fmt, args); + failure_line = line; + failure_file = file; + va_end(args); + + test_failure(); } /** diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h index c44f149f5..da57ab46c 100644 --- a/src/libstrongswan/tests/test_suite.h +++ b/src/libstrongswan/tests/test_suite.h @@ -174,7 +174,11 @@ void test_suite_add_case(test_suite_t *suite, test_case_t *tcase); /** * sigjmp restore point used by test_restore_point */ +#ifdef WIN32 +extern jmp_buf test_restore_point_env; +#else extern sigjmp_buf test_restore_point_env; +#endif /** * Set or return from an execution restore point @@ -185,7 +189,11 @@ extern sigjmp_buf test_restore_point_env; * * @return TRUE if restore point set, FALSE when restored */ -#define test_restore_point() (sigsetjmp(test_restore_point_env, 1) == 0) +#ifdef WIN32 +# define test_restore_point() (setjmp(test_restore_point_env) == 0) +#else +# define test_restore_point() (sigsetjmp(test_restore_point_env, 1) == 0) +#endif /** * Set up signal handlers for test cases @@ -237,6 +245,12 @@ void test_fail_vmsg(const char *file, int line, char *fmt, va_list args); void test_fail_msg(const char *file, int line, char *fmt, ...); /** + * Let a test fail if one of the worker threads has failed (only if called from + * the main thread). + */ +void test_fail_if_worker_failed(); + +/** * Check if two integers equal, fail test if not * * @param a first integer @@ -246,6 +260,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); ({ \ typeof(a) _a = a; \ typeof(b) _b = b; \ + test_fail_if_worker_failed(); \ if (_a != _b) \ { \ test_fail_msg(__FILE__, __LINE__, #a " != " #b " (%d != %d)", _a, _b); \ @@ -262,6 +277,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); ({ \ char* _a = (char*)a; \ char* _b = (char*)b; \ + test_fail_if_worker_failed(); \ if (!_a || !_b || !streq(_a, _b)) \ { \ test_fail_msg(__FILE__, __LINE__, \ @@ -270,12 +286,31 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); }) /** + * Check if two chunks are equal, fail test if not + * + * @param a first chunk + * @param b second chunk + */ +#define test_chunk_eq(a, b) \ +({ \ + chunk_t _a = (chunk_t)a; \ + chunk_t _b = (chunk_t)b; \ + test_fail_if_worker_failed(); \ + if (_a.len != _b.len || !memeq(a.ptr, b.ptr, a.len)) \ + { \ + test_fail_msg(__FILE__, __LINE__, \ + #a " != " #b " (\"%#B\" != \"%#B\")", &_a, &_b); \ + } \ +}) + +/** * Check if a statement evaluates to TRUE, fail test if not * * @param x statement to evaluate */ #define test_assert(x) \ ({ \ + test_fail_if_worker_failed(); \ if (!(x)) \ { \ test_fail_msg(__FILE__, __LINE__, #x); \ @@ -291,6 +326,7 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); */ #define test_assert_msg(x, fmt, ...) \ ({ \ + test_fail_if_worker_failed(); \ if (!(x)) \ { \ test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \ @@ -306,9 +342,11 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); #define ck_assert test_assert #define ck_assert_msg test_assert_msg #define ck_assert_str_eq test_str_eq +#define ck_assert_chunk_eq test_chunk_eq #define fail(fmt, ...) test_fail_msg(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define fail_if(x, fmt, ...) \ ({ \ + test_fail_if_worker_failed(); \ if (x) \ { \ test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \ @@ -323,10 +361,10 @@ void test_fail_msg(const char *file, int line, char *fmt, ...); #define tcase_set_timeout test_case_set_timeout #define suite_add_tcase test_suite_add_case #define START_TEST(name) static void name (int _i) { -#define END_TEST } +#define END_TEST test_fail_if_worker_failed(); } #define START_SETUP(name) static void name() { -#define END_SETUP } +#define END_SETUP test_fail_if_worker_failed(); } #define START_TEARDOWN(name) static void name() { -#define END_TEARDOWN } +#define END_TEARDOWN test_fail_if_worker_failed(); } #endif /** TEST_SUITE_H_ @}*/ diff --git a/src/libstrongswan/tests/tests.c b/src/libstrongswan/tests/tests.c index 9f2adfd15..d95ddd9d5 100644 --- a/src/libstrongswan/tests/tests.c +++ b/src/libstrongswan/tests/tests.c @@ -35,8 +35,14 @@ static bool test_runner_init(bool init) { if (init) { - plugin_loader_add_plugindirs(PLUGINDIR, PLUGINS); - if (!lib->plugins->load(lib->plugins, PLUGINS)) + char *plugins, *plugindir; + + plugins = lib->settings->get_str(lib->settings, + "tests.load", PLUGINS); + plugindir = lib->settings->get_str(lib->settings, + "tests.plugindir", PLUGINDIR); + plugin_loader_add_plugindirs(plugindir, plugins); + if (!lib->plugins->load(lib->plugins, plugins)) { return FALSE; } diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h index 82a5137c1..ab0f642e4 100644 --- a/src/libstrongswan/tests/tests.h +++ b/src/libstrongswan/tests/tests.h @@ -35,6 +35,7 @@ TEST_SUITE(host_suite_create) TEST_SUITE(printf_suite_create) TEST_SUITE(hasher_suite_create) TEST_SUITE(crypter_suite_create) +TEST_SUITE(crypto_factory_suite_create) TEST_SUITE(pen_suite_create) TEST_SUITE(asn1_suite_create) TEST_SUITE(asn1_parser_suite_create) |