From: Sebastian Harl Date: Sat, 26 Apr 2014 20:42:47 +0000 (+0200) Subject: Moved unit tests into t/unit/ subdirectory. X-Git-Tag: sysdb-0.1.0~80 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=cf17313d62dcf1c10df0fe19287e354ede68206b;p=sysdb.git Moved unit tests into t/unit/ subdirectory. --- diff --git a/.gitignore b/.gitignore index 9f1fd8f..0657cd0 100644 --- a/.gitignore +++ b/.gitignore @@ -49,8 +49,8 @@ src/sysdbd sysdb.h # unit testing output -t/libsysdb_test -t/libsysdb_net_test -t/*.log -t/*.trs +t/unit/libsysdb_test +t/unit/libsysdb_net_test +t/unit/*.log +t/unit/*.trs test-driver diff --git a/t/Makefile.am b/t/Makefile.am index 551d863..4764a6e 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -5,35 +5,35 @@ AM_CFLAGS = @STRICT_CFLAGS@ @COVERAGE_CFLAGS@ AM_LDFLAGS = @COVERAGE_LDFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src/include -TESTS = libsysdb_test libsysdb_net_test -check_PROGRAMS = libsysdb_test libsysdb_net_test +TESTS = unit/libsysdb_test unit/libsysdb_net_test +check_PROGRAMS = unit/libsysdb_test unit/libsysdb_net_test -libsysdb_test_SOURCES = \ - libsysdb_test.c libsysdb_test.h \ - libsysdb_testutils.c libsysdb_testutils.h \ - core/data_test.c \ - core/object_test.c \ - core/store_test.c \ - core/store_lookup_test.c \ - core/time_test.c \ - frontend/connection_test.c \ - frontend/parser_test.c \ - frontend/sock_test.c \ - utils/channel_test.c \ - utils/dbi_test.c \ - utils/llist_test.c \ - utils/strbuf_test.c -libsysdb_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ -libsysdb_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@ +unit_libsysdb_test_SOURCES = \ + unit/libsysdb_test.c unit/libsysdb_test.h \ + unit/libsysdb_testutils.c unit/libsysdb_testutils.h \ + unit/core/data_test.c \ + unit/core/object_test.c \ + unit/core/store_test.c \ + unit/core/store_lookup_test.c \ + unit/core/time_test.c \ + unit/frontend/connection_test.c \ + unit/frontend/parser_test.c \ + unit/frontend/sock_test.c \ + unit/utils/channel_test.c \ + unit/utils/dbi_test.c \ + unit/utils/llist_test.c \ + unit/utils/strbuf_test.c +unit_libsysdb_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ -I$(top_srcdir)/t/unit +unit_libsysdb_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@ -libsysdb_net_test_SOURCES = \ - libsysdb_net_test.c libsysdb_test.h \ - libsysdb_testutils.c libsysdb_testutils.h +unit_libsysdb_net_test_SOURCES = \ + unit/libsysdb_net_test.c unit/libsysdb_test.h \ + unit/libsysdb_testutils.c unit/libsysdb_testutils.h if BUILD_WITH_FOPENCOOKIE -libsysdb_net_test_SOURCES += utils/unixsock_test.c +unit_libsysdb_net_test_SOURCES += unit/utils/unixsock_test.c endif -libsysdb_net_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ -libsysdb_net_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@ +unit_libsysdb_net_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ -I$(top_srcdir)/t/unit +unit_libsysdb_net_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@ test: check diff --git a/t/core/data_test.c b/t/core/data_test.c deleted file mode 100644 index 261d5fd..0000000 --- a/t/core/data_test.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SysDB - t/core/data_test.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/data.h" -#include "libsysdb_test.h" - -#include - -START_TEST(test_data) -{ - sdb_data_t d1, d2; - int check; - - d2.type = SDB_TYPE_INTEGER; - d2.data.integer = 4711; - check = sdb_data_copy(&d1, &d2); - fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); - fail_unless(d1.type == d2.type, - "sdb_data_copy() didn't copy type; got: %i; expected: %i", - d1.type, d2.type); - fail_unless(d1.data.integer == d2.data.integer, - "sdb_data_copy() didn't copy integer data: got: %d; expected: %d", - d1.data.integer, d2.data.integer); - - d2.type = SDB_TYPE_DECIMAL; - d2.data.decimal = 47.11; - check = sdb_data_copy(&d1, &d2); - fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); - fail_unless(d1.type == d2.type, - "sdb_data_copy() didn't copy type; got: %i; expected: %i", - d1.type, d2.type); - fail_unless(d1.data.decimal == d2.data.decimal, - "sdb_data_copy() didn't copy decimal data: got: %f; expected: %f", - d1.data.decimal, d2.data.decimal); - - d2.type = SDB_TYPE_STRING; - d2.data.string = "some string"; - check = sdb_data_copy(&d1, &d2); - fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); - fail_unless(d1.type == d2.type, - "sdb_data_copy() didn't copy type; got: %i; expected: %i", - d1.type, d2.type); - fail_unless(!strcmp(d1.data.string, d2.data.string), - "sdb_data_copy() didn't copy string data: got: %s; expected: %s", - d1.data.string, d2.data.string); - - sdb_data_free_datum(&d1); - fail_unless(d1.data.string == NULL, - "sdb_data_free_datum() didn't free string data"); - - d2.type = SDB_TYPE_DATETIME; - d2.data.datetime = 4711; - check = sdb_data_copy(&d1, &d2); - fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); - fail_unless(d1.type == d2.type, - "sdb_data_copy() didn't copy type; got: %i; expected: %i", - d1.type, d2.type); - fail_unless(d1.data.datetime == d2.data.datetime, - "sdb_data_copy() didn't copy datetime data: got: %d; expected: %d", - d1.data.datetime, d2.data.datetime); - - d2.type = SDB_TYPE_BINARY; - d2.data.binary.datum = (unsigned char *)"some string"; - d2.data.binary.length = strlen((const char *)d2.data.binary.datum); - check = sdb_data_copy(&d1, &d2); - fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); - fail_unless(d1.type == d2.type, - "sdb_data_copy() didn't copy type; got: %i; expected: %i", - d1.type, d2.type); - fail_unless(d1.data.binary.length == d2.data.binary.length, - "sdb_data_copy() didn't copy length; got: %d; expected: 5d", - d1.data.binary.length, d2.data.binary.length); - fail_unless(!memcmp(d1.data.binary.datum, d2.data.binary.datum, - d2.data.binary.length), - "sdb_data_copy() didn't copy binary data: got: %s; expected: %s", - d1.data.string, d2.data.string); - - sdb_data_free_datum(&d1); - fail_unless(d1.data.binary.length == 0, - "sdb_data_free_datum() didn't reset binary datum length"); - fail_unless(d1.data.binary.datum == NULL, - "sdb_data_free_datum() didn't free binary datum"); -} -END_TEST - -START_TEST(test_format) -{ - struct { - sdb_data_t datum; - const char *expected; - } golden_data[] = { - { - { SDB_TYPE_INTEGER, { .integer = 4711 } }, - "4711", - }, - { - { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, - "0x1p+16", - }, - { - { SDB_TYPE_STRING, { .string = NULL } }, - "\"NULL\"", - }, - { - { SDB_TYPE_STRING, { .string = "this is a test" } }, - "\"this is a test\"", - }, - { - { SDB_TYPE_STRING, { .string = "special \\ \" characters" } }, - "\"special \\\\ \\\" characters\"", - }, - { - { SDB_TYPE_DATETIME, { .datetime= 471147114711471100 } }, - "\"1984-12-06 02:11:54 +0000\"", - }, - { - { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, - "\"\"", - }, - { - { - SDB_TYPE_BINARY, - { .binary = { 12, (unsigned char *)"binary\0crap\x42" } }, - }, - "\"\\x62\\x69\\x6e\\x61\\x72\\x79\\x0\\x63\\x72\\x61\\x70\\x42\"", - }, - }; - - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_data_t *datum = &golden_data[i].datum; - char buf[sdb_data_strlen(datum) + 2]; - int check; - - memset(buf, (int)'A', sizeof(buf)); - - check = sdb_data_format(datum, buf, sizeof(buf) - 1, - SDB_DOUBLE_QUOTED); - fail_unless(check > 0, - "sdb_data_format(type=%s) = %d; expected: >0", - SDB_TYPE_TO_STRING(datum->type), check); - fail_unless(! strcmp(buf, golden_data[i].expected), - "sdb_data_format(type=%s) used wrong format: %s; expected: %s", - SDB_TYPE_TO_STRING(datum->type), buf, golden_data[i].expected); - - fail_unless((size_t)check <= sizeof(buf) - 2, - "sdb_data_format(type=%s) wrote %d bytes; " - "expected <= %zu based on sdb_data_strlen()", - SDB_TYPE_TO_STRING(datum->type), check, sizeof(buf) - 2); - - fail_unless(buf[sizeof(buf) - 2] == '\0', - "sdb_data_format(type=%s) did not nul-terminate the buffer", - SDB_TYPE_TO_STRING(datum->type)); - fail_unless(buf[sizeof(buf) - 1] == 'A', - "sdb_data_format(type=%s) wrote past the end of the buffer", - SDB_TYPE_TO_STRING(datum->type)); - } -} -END_TEST - -Suite * -core_data_suite(void) -{ - Suite *s = suite_create("core::data"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_data); - tcase_add_test(tc, test_format); - suite_add_tcase(s, tc); - - return s; -} /* core_data_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/core/object_test.c b/t/core/object_test.c deleted file mode 100644 index 85e95c3..0000000 --- a/t/core/object_test.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * SysDB - t/core/object_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/object.h" -#include "libsysdb_test.h" - -#include - -/* - * private data types - */ - -static int init_noop_called = 0; -static int init_noop_retval = 0; -static int -obj_init_noop(sdb_object_t *obj, va_list __attribute__((unused)) ap) -{ - ++init_noop_called; - fail_unless(obj != NULL, "obj init function: received obj == NULL"); - return init_noop_retval; -} /* obj_init_noop */ - -static int destroy_noop_called = 0; -static void -obj_destroy_noop(sdb_object_t *obj) -{ - ++destroy_noop_called; - fail_unless(obj != NULL, "obj destroy function: received obj == NULL"); -} /* obj_destroy_noop */ - -struct noop { - sdb_object_t super; - int data; -}; -static sdb_type_t noop_type = { - /* size = */ sizeof(struct noop), - /* init = */ obj_init_noop, - /* destroy = */ obj_destroy_noop, -}; - -static void *wrapped = (void *)0x42; - -static int destroy_wrapper_called = 0; -static void -wrapper_destroy(void *obj) -{ - ++destroy_wrapper_called; - fail_unless(obj == wrapped, - "wrapper_destroy received unexpected obj %p; expected: %p", - obj, wrapped); -} /* wrapper_destroy */ - -START_TEST(test_obj_create) -{ - sdb_object_t *obj; - sdb_type_t test_type = noop_type; - - const char *name = "test-object"; - - init_noop_called = 0; - init_noop_retval = 0; - destroy_noop_called = 0; - obj = sdb_object_create(name, test_type); - fail_unless(obj != NULL, - "sdb_object_create() = NULL; expected: a new object"); - fail_unless(obj->type.size == test_type.size, - "after sdb_object_create(): type size mismatch; got: %zu; " - "expected: %zu", obj->type.size, test_type.size); - fail_unless(obj->type.init == obj_init_noop, - "after sdb_object_create(): type init = %p; exptected: %p", - obj->type.init, obj_init_noop); - fail_unless(obj->type.destroy == obj_destroy_noop, - "after sdb_object_create(): type destroy = %p; exptected: %p", - obj->type.destroy, obj_destroy_noop); - fail_unless(obj->ref_cnt == 1, - "after sdb_object_create(): obj->ref_cnt = %d; expected: 1", - obj->ref_cnt); - fail_unless(!strcmp(obj->name, "test-object"), - "after sdb_object_create(): obj->name = '%s'; expected: '%s'", - obj->name, name); - fail_unless(obj->name != name, - "after sdb_object_create(): obj->name was not strdup()'ed"); - - fail_unless(init_noop_called == 1, - "sdb_object_create() did not call object's init function"); - fail_unless(destroy_noop_called == 0, - "sdb_object_create() called object's destroy function"); - fail_unless(((struct noop *)obj)->data == 0, - "sdb_object_create() did not initialize data to zero"); - - sdb_object_deref(obj); - fail_unless(destroy_noop_called == 1, - "sdb_object_deref() did not call object's destroy function"); - - init_noop_called = 0; - init_noop_retval = -1; - destroy_noop_called = 0; - obj = sdb_object_create(name, test_type); - fail_unless(obj == NULL, - "sdb_object_create() = %p; expected NULL (init returned -1)", - obj); - fail_unless(init_noop_called == 1, - "sdb_object_create() did not call object's init function"); - fail_unless(destroy_noop_called == 1, - "sdb_object_create() did not call object's destroy function " - "after init failure"); - - test_type.size = 1; - init_noop_called = 0; - init_noop_retval = 0; - destroy_noop_called = 0; - obj = sdb_object_create(name, test_type); - fail_unless(obj == NULL, - "sdb_object_create() = %p; expected NULL (type's size too small)", - obj); - fail_unless(init_noop_called == 0, - "sdb_object_create() called object's init function " - "when size was too small"); - fail_unless(destroy_noop_called == 0, - "sdb_object_create() called object's destroy function " - "when size was too small"); - - test_type.size = sizeof(struct noop); - init_noop_retval = 0; - test_type.init = NULL; - obj = sdb_object_create(name, test_type); - fail_unless(obj != NULL, - "sdb_object_create() fails without init callback"); - sdb_object_deref(obj); - - test_type.destroy = NULL; - obj = sdb_object_create(name, test_type); - fail_unless(obj != NULL, - "sdb_object_create() fails without destroy callback"); - sdb_object_deref(obj); - - init_noop_called = 0; - obj = sdb_object_create_simple(name, sizeof(struct noop), NULL); - fail_unless(obj != NULL, - "sdb_object_create_simple() = NULL; expected: "); - fail_unless(obj->type.size == sizeof(struct noop), - "sdb_object_create_simple() created object of size %zu; " - "expected: %zu", obj->type.size, sizeof(struct noop)); - fail_unless(obj->type.init == NULL, - "sdb_object_create_simple() did not set init=NULL"); - fail_unless(obj->type.destroy == NULL, - "sdb_object_create_simple() did not set destroy=NULL"); - fail_unless(init_noop_called == 0, - "sdb_object_create_simple() unexpectedly called noop's init"); - sdb_object_deref(obj); - - obj = sdb_object_create_T(NULL, struct noop); - fail_unless(obj != NULL, - "sdb_object_create_simple() = NULL; expected: "); - fail_unless(obj->type.size == sizeof(struct noop), - "sdb_object_create_simple() created object of size %zu; " - "expected: %zu", obj->type.size, sizeof(struct noop)); - fail_unless(obj->type.init == NULL, - "sdb_object_create_simple() did not set init=NULL"); - fail_unless(obj->type.destroy == NULL, - "sdb_object_create_simple() did not set destroy=NULL"); - fail_unless(init_noop_called == 0, - "sdb_object_create_simple() unexpectedly called noop's init"); - sdb_object_deref(obj); -} -END_TEST - -START_TEST(test_obj_wrapper) -{ - sdb_object_t *obj; - const char *name = "wrapped-object"; - - destroy_wrapper_called = 0; - obj = sdb_object_create_wrapper(name, wrapped, wrapper_destroy); - fail_unless(obj != NULL, - "sdb_object_create_wrapper() = NULL; expected: wrapper object"); - fail_unless(obj->ref_cnt == 1, - "after sdb_object_create_wrapper(); obj->ref_cnt = %d; " - "expected: 1", obj->ref_cnt); - fail_unless(!strcmp(obj->name, name), - "after sdb_object_create_wrapper(); obj->name = %s; expected: %s", - obj->name, name); - fail_unless(obj->name != name, - "sdb_object_create_wrapper() did not copy object name"); - fail_unless(SDB_OBJ_WRAPPER(obj)->data == wrapped, - "wrapped object wraps unexpected data %p; expected: %p", - SDB_OBJ_WRAPPER(obj)->data, wrapped); - - fail_unless(destroy_wrapper_called == 0, - "sdb_object_create_wrapper() called object's destructor"); - - sdb_object_deref(obj); - fail_unless(destroy_wrapper_called == 1, - "sdb_object_deref() did not call wrapped object's destructor"); -} -END_TEST - -START_TEST(test_obj_ref) -{ - sdb_object_t *obj; - sdb_type_t test_type = noop_type; - - init_noop_called = 0; - init_noop_retval = 0; - destroy_noop_called = 0; - - obj = sdb_object_create("test-object", test_type); - fail_unless(obj != NULL, - "sdb_object_create() = NULL; expected: valid object"); - - sdb_object_ref(obj); - fail_unless(obj->ref_cnt == 2, - "after db_object_ref(): obj->ref_cnt = %d; expected: 2", - obj->ref_cnt); - - sdb_object_ref(obj); - fail_unless(obj->ref_cnt == 3, - "after db_object_ref(): obj->ref_cnt = %d; expected: 3", - obj->ref_cnt); - - obj->ref_cnt = 42; - sdb_object_ref(obj); - fail_unless(obj->ref_cnt == 43, - "after db_object_ref(): obj->ref_cnt = %d; expected: 43", - obj->ref_cnt); - - fail_unless(init_noop_called == 1, - "after some sdb_object_ref(); object's init called %d times; " - "expected: 1", init_noop_called); - fail_unless(destroy_noop_called == 0, - "after some sdb_object_ref(); object's destroy called %d time%s; " - "expected: 0", destroy_noop_called == 1 ? "" : "2", - destroy_noop_called); - - sdb_object_deref(obj); - fail_unless(obj->ref_cnt == 42, - "after db_object_deref(): obj->ref_cnt = %d; expected: 42", - obj->ref_cnt); - - obj->ref_cnt = 23; - sdb_object_deref(obj); - fail_unless(obj->ref_cnt == 22, - "after db_object_deref(): obj->ref_cnt = %d; expected: 22", - obj->ref_cnt); - - fail_unless(init_noop_called == 1, - "after some sdb_object_{de,}ref(); object's init called %d times; " - "expected: 1", init_noop_called); - fail_unless(destroy_noop_called == 0, - "after some sdb_object_{de,}ref(); object's destroy called " - "%d time%s; expected: 0", destroy_noop_called == 1 ? "" : "2", - destroy_noop_called); - - /* test_obj_create already checks the ref_cnt == 1 case */ - obj->ref_cnt = 0; - sdb_object_deref(obj); - fail_unless(init_noop_called == 1, - "after some sdb_object_{de,}ref(); object's init called %d times; " - "expected: 1", init_noop_called); - fail_unless(destroy_noop_called == 1, - "after some sdb_object_{de,}ref(); object's destroy called " - "%d times; expected: 1", destroy_noop_called); - - /* this should work */ - sdb_object_deref(NULL); -} -END_TEST - -START_TEST(test_obj_cmp) -{ - sdb_object_t *obj1, *obj2, *obj3, *obj4; - int status; - - obj1 = sdb_object_create("a", noop_type); - obj2 = sdb_object_create("b", noop_type); - obj3 = sdb_object_create("B", noop_type); - obj4 = sdb_object_create("c", noop_type); - - status = sdb_object_cmp_by_name(obj1, obj2); - fail_unless(status == -1, - "sdb_object_cmp_by_name('a', 'b') = %d; expected: -1", status); - status = sdb_object_cmp_by_name(obj2, obj3); - fail_unless(status == 0, - "sdb_object_cmp_by_name('b', 'B') = %d; expected: 0", status); - status = sdb_object_cmp_by_name(obj4, obj3); - fail_unless(status == 1, - "sdb_object_cmp_by_name('c', 'B') = %d; expected: 1", status); - status = sdb_object_cmp_by_name(obj1, obj1); - fail_unless(status == 0, - "sdb_object_cmp_by_name('a', 'a') = %d; expected: 0", status); - - sdb_object_deref(obj1); - sdb_object_deref(obj2); - sdb_object_deref(obj3); - sdb_object_deref(obj4); -} -END_TEST - -Suite * -core_object_suite(void) -{ - Suite *s = suite_create("core::object"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_obj_create); - tcase_add_test(tc, test_obj_wrapper); - tcase_add_test(tc, test_obj_ref); - tcase_add_test(tc, test_obj_cmp); - suite_add_tcase(s, tc); - - return s; -} /* core_object_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/core/store_lookup_test.c b/t/core/store_lookup_test.c deleted file mode 100644 index 8ead947..0000000 --- a/t/core/store_lookup_test.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * SysDB - t/core/store_lookup_test.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/store.h" -#include "core/store-private.h" -#include "frontend/parser.h" -#include "libsysdb_test.h" - -#include -#include - -static void -populate(void) -{ - const char *hosts[] = { "a", "b", "c" }; - - struct { - const char *host; - const char *service; - } services[] = { - { "a", "s1" }, - { "a", "s2" }, - { "b", "s1" }, - { "b", "s3" }, - }; - - struct { - const char *host; - const char *name; - sdb_data_t value; - } attrs[] = { - { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } }, - }; - - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) { - int status = sdb_store_host(hosts[i], 1); - fail_unless(status == 0, - "sdb_store_host(%s, 1) = %d; expected: 0", - hosts[i], status); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) { - int status = sdb_store_service(services[i].host, - services[i].service, 1); - fail_unless(status == 0, - "sdb_store_service(%s, %s, 1) = %d; expected: 0", - services[i].host, services[i].service, status); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) { - int status = sdb_store_attribute(attrs[i].host, - attrs[i].name, &attrs[i].value, 1); - fail_unless(status == 0, - "sdb_store_attribute(%s, %s, , 1) = %d; expected: 0", - attrs[i].host, attrs[i].name, status); - } -} /* populate */ - -START_TEST(test_store_match) -{ - sdb_store_base_t *obj; - - struct { - const char *hostname; - const char *hostname_re; - - const char *service_name; - const char *service_name_re; - - const char *attr_name; - const char *attr_name_re; - const char *attr_value; - const char *attr_value_re; - - int expected; - } golden_data[] = { - { - /* host */ NULL, NULL, - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "a", NULL, - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "b", NULL, - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ NULL, "^a$", - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ NULL, "^b$", - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "a", "^b$", - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "b", "^a$", - /* svc */ NULL, NULL, - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", NULL, - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ NULL, "^s1$", - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ NULL, NULL, NULL, NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "x1", NULL, - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ NULL, "x", - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ "x1", "x", - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "x", - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ "x1", "s", - /* attr */ NULL, NULL, NULL, NULL, 0 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ "k1", NULL, NULL, NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ NULL, "^k", NULL, NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ NULL, NULL, "v1", NULL, 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ NULL, NULL, NULL, "^v1$", 1 - }, - { - /* host */ "a", "^a$", - /* svc */ "s1", "^s1$", - /* attr */ "k1", "1", "v1", "1", 1 - }, - }; - - size_t i; - - obj = sdb_store_get_host("a"); - fail_unless(obj != NULL, - "sdb_store_get_host(a) = NULL; expected: "); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_store_matcher_t *h, *s, *a, *n; - int status; - - s = sdb_store_service_matcher(golden_data[i].service_name, - golden_data[i].service_name_re, NULL); - fail_unless(s != NULL, - "sdb_store_service_matcher() = NULL; expected: "); - - a = sdb_store_attr_matcher(golden_data[i].attr_name, - golden_data[i].attr_name_re, golden_data[i].attr_value, - golden_data[i].attr_value_re); - fail_unless(a != NULL, - "sdb_store_attr_matcher() = NULL; expected: "); - - h = sdb_store_host_matcher(golden_data[i].hostname, - golden_data[i].hostname_re, s, a); - fail_unless(h != NULL, - "sdb_store_host_matcher() = NULL: expected: "); - /* pass ownership to the host matcher */ - sdb_object_deref(SDB_OBJ(s)); - sdb_object_deref(SDB_OBJ(a)); - - status = sdb_store_matcher_matches(h, obj); - fail_unless(status == golden_data[i].expected, - "sdb_store_matcher_matches({{%s, %s},{%s, %s}," - "{%s, %s, %s, %s}}, ) = %d; expected: %d", - golden_data[i].hostname, golden_data[i].hostname_re, - golden_data[i].service_name, golden_data[i].service_name_re, - golden_data[i].attr_name, golden_data[i].attr_name_re, - golden_data[i].attr_value, golden_data[i].attr_value_re, - status, golden_data[i].expected); - - n = sdb_store_inv_matcher(h); - fail_unless(n != NULL, - "sdb_store_inv_matcher() = NULL; expected: "); - sdb_object_deref(SDB_OBJ(h)); - - /* now match the inverted set of objects */ - status = sdb_store_matcher_matches(n, obj); - fail_unless(status == !golden_data[i].expected, - "sdb_store_matcher_matches(NOT{{%s, %s},{%s, %s}," - "{%s, %s, %s, %s}}, ) = %d; expected: %d", - golden_data[i].hostname, golden_data[i].hostname_re, - golden_data[i].service_name, golden_data[i].service_name_re, - golden_data[i].attr_name, golden_data[i].attr_name_re, - golden_data[i].attr_value, golden_data[i].attr_value_re, - status, !golden_data[i].expected); - - sdb_object_deref(SDB_OBJ(n)); - } - - sdb_object_deref(SDB_OBJ(obj)); -} -END_TEST - -START_TEST(test_store_match_op) -{ - sdb_store_base_t *obj; - - sdb_store_matcher_t *always = sdb_store_host_matcher(NULL, NULL, NULL, NULL); - sdb_store_matcher_t *never = sdb_store_host_matcher("a", "b", NULL, NULL); - - struct { - const char *op; - sdb_store_matcher_t *left; - sdb_store_matcher_t *right; - int expected; - } golden_data[] = { - { "OR", always, always, 1 }, - { "OR", always, never, 1 }, - { "OR", never, always, 1 }, - { "OR", never, never, 0 }, - { "AND", always, always, 1 }, - { "AND", always, never, 0 }, - { "AND", never, always, 0 }, - { "AND", never, never, 0 }, - }; - - int status; - size_t i; - - obj = sdb_store_get_host("a"); - - status = sdb_store_matcher_matches(always, obj); - fail_unless(status == 1, - "INTERNAL ERROR: 'always' did not match host"); - status = sdb_store_matcher_matches(never, obj); - fail_unless(status == 0, - "INTERNAL ERROR: 'never' matches host"); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_store_matcher_t *m; - - if (! strcmp(golden_data[i].op, "OR")) - m = sdb_store_dis_matcher(golden_data[i].left, - golden_data[i].right); - else if (! strcmp(golden_data[i].op, "AND")) - m = sdb_store_con_matcher(golden_data[i].left, - golden_data[i].right); - else { - fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op); - continue; - } - -#define TO_NAME(v) (((v) == always) ? "always" \ - : ((v) == never) ? "never" : "") - - status = sdb_store_matcher_matches(m, obj); - fail_unless(status == golden_data[i].expected, - "%s(%s, %s) = %d; expected: %d", golden_data[i].op, - TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right), - status, golden_data[i].expected); - -#undef TO_NAME - - sdb_object_deref(SDB_OBJ(m)); - } - - sdb_object_deref(SDB_OBJ(always)); - sdb_object_deref(SDB_OBJ(never)); - - sdb_object_deref(SDB_OBJ(obj)); -} -END_TEST - -START_TEST(test_parse_cmp) -{ - sdb_store_matcher_t *check; - - size_t i; - - struct { - const char *obj_type; - const char *attr; - const char *op; - const char *value; - int expected; - } golden_data[] = { - { "host", "name", "=", "hostname", MATCHER_HOST }, - { "host", "name", "!=", "hostname", MATCHER_NOT }, - { "host", "name", "=~", "hostname", MATCHER_HOST }, - { "host", "name", "!~", "hostname", MATCHER_NOT }, - { "host", "attr", "=", "hostname", -1 }, - { "host", "attr", "!=", "hostname", -1 }, - { "host", "name", "&^", "hostname", -1 }, - { "service", "name", "=", "srvname", MATCHER_HOST }, - { "service", "name", "!=", "srvname", MATCHER_NOT }, - { "service", "name", "=~", "srvname", MATCHER_HOST }, - { "service", "name", "!~", "srvname", MATCHER_NOT }, - { "service", "attr", "=", "srvname", -1 }, - { "service", "attr", "!=", "srvname", -1 }, - { "service", "name", "&^", "srvname", -1 }, - { "attribute", "name", "=", "attrname", MATCHER_HOST }, - { "attribute", "name", "!=", "attrname", MATCHER_NOT }, - { "attribute", "name", "=~", "attrname", MATCHER_HOST }, - { "attribute", "name", "!~", "attrname", MATCHER_NOT }, - { "attribute", "attr", "=", "attrname", MATCHER_HOST }, - { "attribute", "attr", "!=", "attrname", MATCHER_NOT }, - { "attribute", "attr", "=~", "attrname", MATCHER_HOST }, - { "attribute", "attr", "!~", "attrname", MATCHER_NOT }, - { "attribute", "attr", "&^", "attrname", -1 }, - }; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - check = sdb_store_matcher_parse_cmp(golden_data[i].obj_type, - golden_data[i].attr, golden_data[i].op, golden_data[i].value); - - if (golden_data[i].expected == -1) { - fail_unless(check == NULL, - "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; " - "expected: NULL", golden_data[i].obj_type, - golden_data[i].attr, golden_data[i].op, - golden_data[i].value, check); - continue; - } - - fail_unless(check != NULL, - "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; " - "expected: NULL", golden_data[i].obj_type, - golden_data[i].attr, golden_data[i].op, - golden_data[i].value, check); - fail_unless(M(check)->type == golden_data[i].expected, - "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) returned matcher " - "of type %d; expected: %d", golden_data[i].obj_type, - golden_data[i].attr, golden_data[i].op, golden_data[i].value, - M(check)->type, golden_data[i].expected); - - sdb_object_deref(SDB_OBJ(check)); - } -} -END_TEST - -static int -lookup_cb(sdb_store_base_t *obj, void *user_data) -{ - int *i = user_data; - - fail_unless(obj != NULL, - "sdb_store_lookup callback received NULL obj; expected: " - ""); - fail_unless(i != NULL, - "sdb_store_lookup callback received NULL user_data; " - "expected: "); - - ++(*i); - return 0; -} /* lookup_cb */ - -START_TEST(test_lookup) -{ -#define PTR_RE "0x[0-9a-f]+" - struct { - const char *query; - int expected; - const char *tostring_re; - } golden_data[] = { - { "host.name = 'a'", 1, - "HOST\\{ NAME\\{ 'a', \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, - { "host.name =~ 'a|b'", 2, - "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, - { "host.name =~ 'host'", 0, - "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, - { "host.name =~ '.'", 3, - "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, - { "service.name = 's1'", 2, - "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " - "NAME\\{ 's1', \\(nil\\) }, ATTR\\{\\} " - "\\}, ATTR\\{\\} \\}" }, - { "service.name =~ 's'", 2, - "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " - "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " - "\\}, ATTR\\{\\} \\}" }, - { "service.name !~ 's'", 1, - "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " - "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " - "\\}, ATTR\\{\\} \\})" }, - { "attribute.name = 'k1'", 1, - "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " - "\\} \\}" }, - { "attribute.name = 'x'", 0, - "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " - "\\} \\}" }, - { "attribute.k1 = 'v1'", 1, - "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " - "\\} \\}" }, - { "attribute.k1 != 'v1'", 2, - "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " - "\\} \\})" }, - { "attribute.k1 != 'v2'", 3, - "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v2', \\(nil\\) \\} " - "\\} \\})" }, - { "attribute.name != 'x' " - "AND attribute.y !~ 'x'", 3, - "\\(AND, \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " - "\\} \\}\\), \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " - "NAME\\{ 'y', \\(nil\\) }, VALUE\\{ NULL, "PTR_RE" \\} " - "\\} \\}\\)\\)" }, - }; - - int check, n; - size_t i; - - n = 0; - check = sdb_store_lookup(NULL, lookup_cb, &n); - fail_unless(check == 0, - "sdb_store_lookup() = %d; expected: 0", check); - fail_unless(n == 3, - "sdb_store_lookup called callback %d times; expected: 3", (int)n); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_store_matcher_t *m; - char buf[4096]; - - m = sdb_fe_parse_matcher(golden_data[i].query, -1); - fail_unless(m != NULL, - "sdb_fe_parse_matcher(%s, -1) = NULL; expected: ", - golden_data[i].query); - fail_unless(sdb_regmatches(golden_data[i].tostring_re, - sdb_store_matcher_tostring(m, buf, sizeof(buf))) == 0, - "sdb_fe_parse_matcher(%s, -1) = %s; expected: %s", - golden_data[i].query, - sdb_store_matcher_tostring(m, buf, sizeof(buf)), - golden_data[i].tostring_re); - - n = 0; - sdb_store_lookup(m, lookup_cb, &n); - fail_unless(n == golden_data[i].expected, - "sdb_store_lookup(matcher{%s}) found %d hosts; expected: %d", - golden_data[i].query, n, golden_data[i].expected); - sdb_object_deref(SDB_OBJ(m)); - } -} -END_TEST - -Suite * -core_store_lookup_suite(void) -{ - Suite *s = suite_create("core::store_lookup"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, populate, sdb_store_clear); - tcase_add_test(tc, test_store_match); - tcase_add_test(tc, test_store_match_op); - tcase_add_test(tc, test_parse_cmp); - tcase_add_test(tc, test_lookup); - suite_add_tcase(s, tc); - - return s; -} /* core_store_lookup_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/core/store_test.c b/t/core/store_test.c deleted file mode 100644 index 29c5b1b..0000000 --- a/t/core/store_test.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * SysDB - t/core/store_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/store.h" -#include "core/store-private.h" -#include "libsysdb_test.h" - -#include -#include - -static void -populate(void) -{ - sdb_data_t datum; - - sdb_store_host("h1", 1); - sdb_store_host("h2", 1); - - datum.type = SDB_TYPE_STRING; - datum.data.string = "v1"; - sdb_store_attribute("h1", "k1", &datum, 1); - datum.data.string = "v2"; - sdb_store_attribute("h1", "k2", &datum, 1); - datum.data.string = "v3"; - sdb_store_attribute("h1", "k3", &datum, 1); - - sdb_store_service("h2", "s1", 1); - sdb_store_service("h2", "s2", 1); -} /* populate */ - -START_TEST(test_store_host) -{ - struct { - const char *name; - sdb_time_t last_update; - int expected; - } golden_data[] = { - { "a", 2, 0 }, - { "a", 3, 0 }, - { "a", 1, 1 }, - { "b", 2, 0 }, - { "b", 1, 1 }, - { "A", 1, 1 }, /* case-insensitive */ - { "A", 4, 0 }, - }; - - struct { - const char *name; - _Bool has; - } golden_hosts[] = { - { "a", 1 == 1 }, - { "b", 1 == 1 }, - { "c", 0 == 1 }, - { "A", 1 == 1 }, - }; - - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int status; - - status = sdb_store_host(golden_data[i].name, - golden_data[i].last_update); - fail_unless(status == golden_data[i].expected, - "sdb_store_host(%s, %d) = %d; expected: %d", - golden_data[i].name, (int)golden_data[i].last_update, - status, golden_data[i].expected); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { - _Bool has; - - has = sdb_store_has_host(golden_hosts[i].name); - fail_unless(has == golden_hosts[i].has, - "sdb_store_has_host(%s) = %d; expected: %d", - golden_hosts[i].name, has, golden_hosts[i].has); - } -} -END_TEST - -START_TEST(test_store_get_host) -{ - char *golden_hosts[] = { "a", "b", "c" }; - char *unknown_hosts[] = { "x", "y", "z" }; - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { - int status = sdb_store_host(golden_hosts[i], 1); - fail_unless(status >= 0, - "sdb_store_host(%s) = %d; expected: >=0", - golden_hosts[i], status); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { - sdb_store_base_t *sobj1, *sobj2; - int ref_cnt; - - fail_unless(sdb_store_has_host(golden_hosts[i]), - "sdb_store_has_host(%s) = FALSE; expected: TRUE", - golden_hosts[i]); - - sobj1 = sdb_store_get_host(golden_hosts[i]); - fail_unless(sobj1 != NULL, - "sdb_store_get_host(%s) = NULL; expected: ", - golden_hosts[i]); - ref_cnt = SDB_OBJ(sobj1)->ref_cnt; - - fail_unless(ref_cnt > 1, - "sdb_store_get_host(%s) did not increment ref count: " - "got: %d; expected: >1", golden_hosts[i], ref_cnt); - - sobj2 = sdb_store_get_host(golden_hosts[i]); - fail_unless(sobj2 != NULL, - "sdb_store_get_host(%s) = NULL; expected: ", - golden_hosts[i]); - - fail_unless(sobj1 == sobj2, - "sdb_store_get_host(%s) returned different objects " - "in successive calls", golden_hosts[i]); - fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1, - "sdb_store_get_hosts(%s) did not increment ref count " - "(first call: %d; second call: %d)", - golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt); - - sdb_object_deref(SDB_OBJ(sobj1)); - sdb_object_deref(SDB_OBJ(sobj2)); - } - for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) { - sdb_store_base_t *sobj; - - fail_unless(!sdb_store_has_host(unknown_hosts[i]), - "sdb_store_has_host(%s) = TRUE; expected: FALSE", - unknown_hosts[i]); - - sobj = sdb_store_get_host(unknown_hosts[i]); - fail_unless(!sobj, "sdb_store_get_host(%s) = ; expected: NULL", - unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL"); - } -} -END_TEST - -START_TEST(test_store_attr) -{ - struct { - const char *host; - const char *key; - char *value; - sdb_time_t last_update; - int expected; - } golden_data[] = { - { "k", "k", "v", 1, -1 }, - { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */ - { "l", "k1", "v1", 1, 0 }, - { "l", "k1", "v2", 2, 0 }, - { "l", "k1", "v3", 1, 1 }, - { "l", "k2", "v1", 1, 0 }, - { "m", "k", "v1", 2, 0 }, - { "m", "k", "v2", 1, 1 }, - }; - - size_t i; - - sdb_store_host("l", 1); - sdb_store_host("m", 1); - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_data_t datum; - int status; - - /* XXX: test other types as well */ - datum.type = SDB_TYPE_STRING; - datum.data.string = golden_data[i].value; - - status = sdb_store_attribute(golden_data[i].host, - golden_data[i].key, &datum, - golden_data[i].last_update); - fail_unless(status == golden_data[i].expected, - "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d", - golden_data[i].host, golden_data[i].key, golden_data[i].value, - golden_data[i].last_update, status, golden_data[i].expected); - } -} -END_TEST - -START_TEST(test_store_service) -{ - struct { - const char *host; - const char *svc; - sdb_time_t last_update; - int expected; - } golden_data[] = { - { "k", "s", 1, -1 }, - { "k", "s", 1, -1 }, /* retry to ensure the host is not created */ - { "l", "s1", 1, 0 }, - { "l", "s1", 2, 0 }, - { "l", "s1", 1, 1 }, - { "l", "s2", 1, 0 }, - { "m", "s", 2, 0 }, - { "m", "s", 1, 1 }, - }; - - size_t i; - - sdb_store_host("m", 1); - sdb_store_host("l", 1); - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int status; - - status = sdb_store_service(golden_data[i].host, - golden_data[i].svc, golden_data[i].last_update); - fail_unless(status == golden_data[i].expected, - "sdb_store_service(%s, %s, %d) = %d; expected: %d", - golden_data[i].host, golden_data[i].svc, - golden_data[i].last_update, status, golden_data[i].expected); - } -} -END_TEST - -static void -verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags) -{ - int pos; - size_t len1, len2; - size_t i; - - len1 = strlen(sdb_strbuf_string(buf)); - len2 = strlen(expected); - - pos = -1; - if (len1 != len2) - pos = (int)(len1 <= len2 ? len1 : len2); - - for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) { - if (sdb_strbuf_string(buf)[i] != expected[i]) { - pos = (int)i; - break; - } - } - - fail_unless(pos == -1, - "sdb_store_tojson(%x) returned unexpected result\n" - " got: %s\n %*s\n expected: %s", - flags, sdb_strbuf_string(buf), pos + 1, "^", expected); -} /* verify_json_output */ - -START_TEST(test_store_tojson) -{ - sdb_strbuf_t *buf; - size_t i; - - struct { - int flags; - const char *expected; - } golden_data[] = { - { 0, "{\"hosts\":[" - "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"attributes\": [" - "{\"name\": \"k1\", \"value\": \"v1\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"k2\", \"value\": \"v2\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"k3\", \"value\": \"v3\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}" - "], " - "\"services\": []}," - "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"attributes\": [], " - "\"services\": [" - "{\"name\": \"s1\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"s2\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}" - "]}" - "]}" }, - { SDB_SKIP_SERVICES, - "{\"hosts\":[" - "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"attributes\": [" - "{\"name\": \"k1\", \"value\": \"v1\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"k2\", \"value\": \"v2\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"k3\", \"value\": \"v3\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}" - "]}," - "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"attributes\": []}" - "]}" }, - { SDB_SKIP_ATTRIBUTES, - "{\"hosts\":[" - "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"services\": []}," - "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\", " - "\"services\": [" - "{\"name\": \"s1\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"s2\", " - "\"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}" - "]}" - "]}" }, - { SDB_SKIP_SERVICES | SDB_SKIP_ATTRIBUTES, - "{\"hosts\":[" - "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}," - "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " - "\"update_interval\": \"0s\"}" - "]}" }, - }; - - buf = sdb_strbuf_create(0); - fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer"); - populate(); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int status; - - sdb_strbuf_clear(buf); - - status = sdb_store_tojson(buf, golden_data[i].flags); - fail_unless(status == 0, - "sdb_store_tojson(%x) = %d; expected: 0", - golden_data[i].flags, status); - - verify_json_output(buf, golden_data[i].expected, golden_data[i].flags); - } - sdb_strbuf_destroy(buf); -} -END_TEST - -START_TEST(test_interval) -{ - sdb_store_base_t *host; - - /* 10 us interval */ - sdb_store_host("host", 10); - sdb_store_host("host", 20); - sdb_store_host("host", 30); - sdb_store_host("host", 40); - - host = sdb_store_get_host("host"); - fail_unless(host != NULL, - "INTERNAL ERROR: store doesn't have host after adding it"); - - fail_unless(host->interval == 10, - "sdb_store_host() did not calculate interval correctly: " - "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 10); - - /* multiple updates for the same timestamp don't modify the interval */ - sdb_store_host("host", 40); - sdb_store_host("host", 40); - sdb_store_host("host", 40); - sdb_store_host("host", 40); - - fail_unless(host->interval == 10, - "sdb_store_host() changed interval when doing multiple updates " - "using the same timestamp; got: %"PRIscTIME"; " - "expected: %"PRIscTIME, host->interval, 10); - - /* multiple updates using an timestamp don't modify the interval */ - sdb_store_host("host", 20); - sdb_store_host("host", 20); - sdb_store_host("host", 20); - sdb_store_host("host", 20); - - fail_unless(host->interval == 10, - "sdb_store_host() changed interval when doing multiple updates " - "using an old timestamp; got: %"PRIscTIME"; expected: %"PRIscTIME, - host->interval, 10); - - /* new interval: 20 us */ - sdb_store_host("host", 60); - fail_unless(host->interval == 11, - "sdb_store_host() did not calculate interval correctly: " - "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 11); - - /* new interval: 40 us */ - sdb_store_host("host", 100); - fail_unless(host->interval == 13, - "sdb_store_host() did not calculate interval correctly: " - "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 11); - - sdb_object_deref(SDB_OBJ(host)); -} -END_TEST - -static int -iter_incr(sdb_store_base_t *obj, void *user_data) -{ - intptr_t *i = user_data; - - fail_unless(obj != NULL, - "sdb_store_iterate callback received NULL obj; expected: " - ""); - fail_unless(i != NULL, - "sdb_store_iterate callback received NULL user_data; " - "expected: "); - - ++(*i); - return 0; -} /* iter_incr */ - -static int -iter_error(sdb_store_base_t *obj, void *user_data) -{ - intptr_t *i = user_data; - - fail_unless(obj != NULL, - "sdb_store_iterate callback received NULL obj; expected: " - ""); - fail_unless(i != NULL, - "sdb_store_iterate callback received NULL user_data; " - "expected: "); - - ++(*i); - return -1; -} /* iter_error */ - -START_TEST(test_iterate) -{ - intptr_t i = 0; - int check; - - /* empty store */ - check = sdb_store_iterate(iter_incr, &i); - fail_unless(check == -1, - "sdb_store_iterate(), empty store = %d; expected: -1", check); - fail_unless(i == 0, - "sdb_store_iterate called callback %d times; expected: 0", (int)i); - - populate(); - - check = sdb_store_iterate(iter_incr, &i); - fail_unless(check == 0, - "sdb_store_iterate() = %d; expected: 0", check); - fail_unless(i == 2, - "sdb_store_iterate called callback %d times; expected: 1", (int)i); - - i = 0; - check = sdb_store_iterate(iter_error, &i); - fail_unless(check == -1, - "sdb_store_iterate(), error callback = %d; expected: -1", check); - fail_unless(i == 1, - "sdb_store_iterate called callback %d times " - "(callback returned error); expected: 1", (int)i); -} -END_TEST - -Suite * -core_store_suite(void) -{ - Suite *s = suite_create("core::store"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_store_tojson); - tcase_add_test(tc, test_store_host); - tcase_add_test(tc, test_store_get_host); - tcase_add_test(tc, test_store_attr); - tcase_add_test(tc, test_store_service); - tcase_add_test(tc, test_interval); - tcase_add_test(tc, test_iterate); - tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear); - suite_add_tcase(s, tc); - - return s; -} /* core_store_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/core/time_test.c b/t/core/time_test.c deleted file mode 100644 index f22e236..0000000 --- a/t/core/time_test.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SysDB - t/core/time_test.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/time.h" -#include "libsysdb_test.h" - -#include - -START_TEST(test_strfinterval) -{ - char buf[1024]; - size_t check; - size_t i; - - struct { - sdb_time_t interval; - const char *expected; - } golden_data[] = { - { 0, "0s" }, - { 4711, ".000004711s" }, - { 1000123400, "1.0001234s" }, - { 47940228000000000L, "1Y6M7D" }, - { SDB_INTERVAL_YEAR, "1Y" }, - { SDB_INTERVAL_MONTH, "1M" }, - { SDB_INTERVAL_DAY, "1D" }, - { SDB_INTERVAL_HOUR, "1h" }, - { SDB_INTERVAL_MINUTE, "1m" }, - { SDB_INTERVAL_SECOND, "1s" }, - { SDB_INTERVAL_YEAR - + SDB_INTERVAL_MONTH - + SDB_INTERVAL_DAY - + SDB_INTERVAL_HOUR - + SDB_INTERVAL_MINUTE - + SDB_INTERVAL_SECOND - + 1234, "1Y1M1D1h1m1.000001234s" }, - }; - - /* this should return the number of bytes which would have been written; - * most notably, it should not segfault ;-) */ - check = sdb_strfinterval(NULL, 0, 4711); /* expected: .000004711s */ - fail_unless(check == 11, - "sdb_strfinterval(NULL, 0, 4711) = %zu; expected: 11", check); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - check = sdb_strfinterval(buf, sizeof(buf), golden_data[i].interval); - fail_unless(check > 0, - "sdb_strfinterval(, , %"PRIscTIME") = %zu; " - "expected: >0", golden_data[i].interval, check); - fail_unless(!strcmp(buf, golden_data[i].expected), - "sdb_strfinterval(, , %"PRIscTIME") did not " - "format interval correctly; got: '%s'; expected: '%s'", - golden_data[i].interval, buf, golden_data[i].expected); - fail_unless(check == strlen(golden_data[i].expected), - "sdb_strfinterval(, , %"PRIscTIME") = %zu; " - "expected: %zu", golden_data[i].interval, check, - strlen(golden_data[i].expected)); - } -} -END_TEST - -Suite * -core_time_suite(void) -{ - Suite *s = suite_create("core::time"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_strfinterval); - suite_add_tcase(s, tc); - - return s; -} /* core_time_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/frontend/connection_test.c b/t/frontend/connection_test.c deleted file mode 100644 index 9851a86..0000000 --- a/t/frontend/connection_test.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * SysDB - t/frontend/connection_test.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "frontend/connection.h" -#include "frontend/connection-private.h" -#include "libsysdb_test.h" - -#include "utils/strbuf.h" - -#include - -#include -#include -#include - -#include - -#include -#include -#include - -/* - * private helper functions - */ - -static void -mock_conn_destroy(sdb_conn_t *conn) -{ - if (SDB_OBJ(conn)->name) - free(SDB_OBJ(conn)->name); - sdb_strbuf_destroy(conn->buf); - sdb_strbuf_destroy(conn->errbuf); - if (conn->fd >= 0) - close(conn->fd); - free(conn); -} /* mock_conn_destroy */ - -static sdb_conn_t * -mock_conn_create(void) -{ - sdb_conn_t *conn; - - char tmp_file[] = "connection_test_socket.XXXXXX"; - - conn = calloc(1, sizeof(*conn)); - if (! conn) { - fail("INTERNAL ERROR: failed to allocate connection object"); - return NULL; - } - - SDB_OBJ(conn)->name = strdup("mock_connection"); - SDB_OBJ(conn)->ref_cnt = 1; - - conn->buf = sdb_strbuf_create(0); - conn->errbuf = sdb_strbuf_create(0); - if ((! conn->buf) || (! conn->errbuf)) { - mock_conn_destroy(conn); - fail("INTERNAL ERROR: failed to allocate connection object"); - return NULL; - } - - conn->fd = mkstemp(tmp_file); - if (conn->fd < 0) { - mock_conn_destroy(conn); - fail("INTERNAL ERROR: failed to allocate connection object"); - return NULL; - } - - unlink(tmp_file); - - conn->cmd = CONNECTION_IDLE; - conn->cmd_len = 0; - return conn; -} /* mock_conn_create */ - -static void -mock_conn_rewind(sdb_conn_t *conn) -{ - lseek(conn->fd, 0, SEEK_SET); -} /* mock_conn_rewind */ - -static void -mock_conn_truncate(sdb_conn_t *conn) -{ - lseek(conn->fd, 0, SEEK_SET); - ftruncate(conn->fd, 0); -} /* mock_conn_truncate */ - -static int -mock_unixsock_listener(char *sock_path) -{ - struct sockaddr_un sa; - char *filename; - int fd, status; - - filename = tmpnam(sock_path); - fail_unless(filename != NULL, - "INTERNAL ERROR: tmpnam() = NULL; expected: a string"); - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - fail_unless(fd >= 0, - "INTERNAL ERROR: socket() = %d; expected: >=0", fd); - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)); - - status = bind(fd, (struct sockaddr *)&sa, sizeof(sa)); - fail_unless(status == 0, - "INTERNAL ERROR: bind() = %d; expected: 0", status); - status = listen(fd, 32); - fail_unless(status == 0, - "INTERNAL ERROR: listen() = %d; expected: 0", status); - - return fd; -} /* mock_unixsock */ - -static void * -mock_client(void *arg) -{ - char *socket_path = arg; - - struct sockaddr_un sa; - int fd, check; - - fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0); - fail_unless(fd >= 0, - "INTERNAL ERROR: socket() = %d; expected: >= 0", fd); - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, socket_path, sizeof(sa.sun_path)); - - check = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); - fail_unless(check == 0, - "INTERNAL ERROR: connect() = %d; expected: 0", check); - - close(fd); - return NULL; -} /* mock_client */ - -/* - * tests - */ - -START_TEST(test_conn_accept) -{ - char socket_path[L_tmpnam]; - int fd, check; - - sdb_conn_t *conn; - - pthread_t thr; - - conn = sdb_connection_accept(-1); - fail_unless(conn == NULL, - "sdb_connection_accept(-1) = %p; expected: NULL", conn); - - memset(&socket_path, 0, sizeof(socket_path)); - fd = mock_unixsock_listener(socket_path); - check = pthread_create(&thr, /* attr = */ NULL, mock_client, socket_path); - fail_unless(check == 0, - "INTERNAL ERROR: pthread_create() = %i; expected: 0", check); - - conn = sdb_connection_accept(fd); - fail_unless(conn != NULL, - "sdb_connection_accept(%d) = %p; expected: ", fd, conn); - - unlink(socket_path); - sdb_connection_close(conn); - pthread_join(thr, NULL); -} -END_TEST - -START_TEST(test_conn_setup) -{ - sdb_conn_t *conn = mock_conn_create(); - - struct { - uint32_t code; - const char *msg; - const char *err; - } golden_data[] = { - { UINT32_MAX, NULL, NULL }, - { CONNECTION_IDLE, "fakedata", NULL }, - { CONNECTION_PING, NULL, "Authentication required" }, - { CONNECTION_STARTUP, "fakeuser", NULL }, - { CONNECTION_PING, NULL, NULL }, - { CONNECTION_IDLE, NULL, NULL }, - { CONNECTION_PING, "fakedata", NULL }, - { CONNECTION_IDLE, NULL, NULL }, - }; - - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - ssize_t check, expected = 0; - - mock_conn_truncate(conn); - - if (golden_data[i].code != UINT32_MAX) { - expected = 2 * sizeof(uint32_t) - + (golden_data[i].msg ? strlen(golden_data[i].msg) : 0); - - check = sdb_connection_send(conn, golden_data[i].code, - (uint32_t)(golden_data[i].msg - ? strlen(golden_data[i].msg) : 0), - golden_data[i].msg); - fail_unless(check == expected, - "sdb_connection_send(%d, %s) = %zi; expected: %zi", - golden_data[i].code, - golden_data[i].msg ? golden_data[i].msg : "", - check, expected); - } - - mock_conn_rewind(conn); - check = sdb_connection_read(conn); - fail_unless(check == expected, - "sdb_connection_read() = %zi; expected: %zi", - check, expected); - - fail_unless(sdb_strbuf_len(conn->buf) == 0, - "sdb_connection_read() left %zu bytes in the buffer; " - "expected: 0", sdb_strbuf_len(conn->buf)); - - if (golden_data[i].err) { - const char *err = sdb_strbuf_string(conn->errbuf); - fail_unless(strcmp(err, golden_data[i].err) == 0, - "sdb_connection_read(): got error '%s'; " - "expected: '%s'", err, golden_data[i].err); - } - else - fail_unless(sdb_strbuf_len(conn->errbuf) == 0, - "sdb_connection_read() left %zu bytes in the error " - "buffer; expected: 0", sdb_strbuf_len(conn->errbuf)); - } - - mock_conn_destroy(conn); -} -END_TEST - -Suite * -fe_conn_suite(void) -{ - Suite *s = suite_create("frontend::connection"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_conn_accept); - tcase_add_test(tc, test_conn_setup); - suite_add_tcase(s, tc); - - return s; -} /* fe_conn_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/frontend/parser_test.c b/t/frontend/parser_test.c deleted file mode 100644 index f64b9eb..0000000 --- a/t/frontend/parser_test.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * SysDB - t/frontend/parser_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "frontend/connection.h" -#include "frontend/parser.h" -#include "core/store-private.h" -#include "core/object.h" -#include "libsysdb_test.h" - -#include - -/* - * tests - */ - -START_TEST(test_parse) -{ - struct { - const char *query; - int len; - int expected; - sdb_conn_state_t expected_cmd; - } golden_data[] = { - /* empty commands */ - { NULL, -1, -1, 0 }, - { "", -1, 0, 0 }, - { ";", -1, 0, 0 }, - { ";;", -1, 0, 0 }, - - /* valid commands */ - { "FETCH 'host'", -1, 1, CONNECTION_FETCH }, - { "LIST", -1, 1, CONNECTION_LIST }, - { "LIST -- comment", -1, 1, CONNECTION_LIST }, - { "LIST;", -1, 1, CONNECTION_LIST }, - { "LIST; INVALID", 5, 1, CONNECTION_LIST }, - - { "LOOKUP hosts WHERE " - "host.name = 'host'", -1, 1, CONNECTION_LOOKUP }, - { "LOOKUP hosts WHERE NOT " - "host.name = 'host'", -1, 1, CONNECTION_LOOKUP }, - { "LOOKUP hosts WHERE " - "host.name =~ 'p' AND " - "service.name =~ 'p'", -1, 1, CONNECTION_LOOKUP }, - { "LOOKUP hosts WHERE NOT " - "host.name =~ 'p' AND " - "service.name =~ 'p'", -1, 1, CONNECTION_LOOKUP }, - { "LOOKUP hosts WHERE " - "host.name =~ 'p' AND " - "service.name =~ 'p' OR " - "service.name =~ 'r'", -1, 1, CONNECTION_LOOKUP }, - { "LOOKUP hosts WHERE NOT " - "host.name =~ 'p' AND " - "service.name =~ 'p' OR " - "service.name =~ 'r'", -1, 1, CONNECTION_LOOKUP }, - - /* comments */ - { "/* some comment */", -1, 0, 0 }, - { "-- another comment", -1, 0, 0 }, - - /* syntax errors */ - { "INVALID", -1, -1, 0 }, - { "FETCH host", -1, -1, 0 }, - { "LIST; INVALID", 8, -1, 0 }, - { "/* some incomplete", -1, -1, 0 }, - - { "LOOKUP hosts", -1, -1, 0 }, - { "LOOKUP foo WHERE " - "host.name = 'host'", -1, -1, 0 }, - }; - - size_t i; - sdb_llist_t *check; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_object_t *obj; - _Bool ok; - - check = sdb_fe_parse(golden_data[i].query, golden_data[i].len); - if (golden_data[i].expected < 0) - ok = check == 0; - else - ok = sdb_llist_len(check) == (size_t)golden_data[i].expected; - - fail_unless(ok, "sdb_fe_parse(%s) = %p (len: %zu); expected: %d", - golden_data[i].query, check, sdb_llist_len(check), - golden_data[i].expected); - - if (! check) - continue; - - if ((! golden_data[i].expected_cmd) - || (golden_data[i].expected <= 0)) { - sdb_llist_destroy(check); - continue; - } - - obj = sdb_llist_get(check, 0); - fail_unless(SDB_CONN_NODE(obj)->cmd == golden_data[i].expected_cmd, - "sdb_fe_parse(%s)->cmd = %i; expected: %d", - golden_data[i].query, SDB_CONN_NODE(obj)->cmd, - golden_data[i].expected_cmd); - sdb_object_deref(obj); - sdb_llist_destroy(check); - } -} -END_TEST - -START_TEST(test_parse_matcher) -{ - struct { - const char *expr; - int len; - int expected; - } golden_data[] = { - /* empty expressions */ - { NULL, -1, -1 }, - { "", -1, -1 }, - - /* valid expressions */ - { "host.name = 'localhost'", -1, MATCHER_HOST }, - { "host.name != 'localhost'", -1, MATCHER_NOT }, - { "host.name =~ 'host'", -1, MATCHER_HOST }, - { "host.name !~ 'host'", -1, MATCHER_NOT }, - { "host.name = 'localhost' -- foo", -1, MATCHER_HOST }, - { "host.name = 'host' ", 18, MATCHER_HOST }, - /* match hosts by service */ - { "service.name = 'name'", -1, MATCHER_HOST }, - { "service.name != 'name'", -1, MATCHER_NOT }, - { "service.name =~ 'pattern'", -1, MATCHER_HOST }, - { "service.name !~ 'pattern'", -1, MATCHER_NOT }, - /* match hosts by attribute */ - { "attribute.name = 'name'", -1, MATCHER_HOST }, - { "attribute.name != 'name'", -1, MATCHER_NOT }, - { "attribute.name =~ 'pattern'", -1, MATCHER_HOST }, - { "attribute.name !~ 'pattern'", -1, MATCHER_NOT }, - /* composite expressions */ - { "host.name =~ 'pattern' AND " - "service.name =~ 'pattern'", -1, MATCHER_AND }, - { "host.name =~ 'pattern' OR " - "service.name =~ 'pattern'", -1, MATCHER_OR }, - { "NOT host.name = 'host'", -1, MATCHER_NOT }, - - /* check operator precedence */ - { "host.name = 'name' OR " - "service.name = 'name' AND " - "attribute.name = 'name' OR " - "attribute.foo = 'bar'", -1, MATCHER_OR }, - { "host.name = 'name' AND " - "service.name = 'name' AND " - "attribute.name = 'name' OR " - "attribute.foo = 'bar'", -1, MATCHER_OR }, - { "host.name = 'name' AND " - "service.name = 'name' OR " - "attribute.name = 'name' AND " - "attribute.foo = 'bar'", -1, MATCHER_OR }, - { "(host.name = 'name' OR " - "service.name = 'name') AND " - "(attribute.name = 'name' OR " - "attribute.foo = 'bar')", -1, MATCHER_AND }, - { "NOT host.name = 'name' OR " - "service.name = 'name'", -1, MATCHER_OR }, - { "NOT host.name = 'name' OR " - "NOT service.name = 'name'", -1, MATCHER_OR }, - { "NOT (host.name = 'name' OR " - "NOT service.name = 'name')", -1, MATCHER_NOT }, - - /* syntax errors */ - { "LIST", -1, -1 }, - { "foo &^ bar", -1, -1 }, - }; - - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_store_matcher_t *m; - m = sdb_fe_parse_matcher(golden_data[i].expr, golden_data[i].len); - - if (golden_data[i].expected < 0) { - fail_unless(m == NULL, - "sdb_fe_parse_matcher(%s) = %p; expected: NULL", - golden_data[i].expr, m); - continue; - } - - fail_unless(m != NULL, "sdb_fe_parse_matcher(%s) = NULL; " - "expected: ", golden_data[i].expr); - fail_unless(M(m)->type == golden_data[i].expected, - "sdb_fe_parse_matcher(%s) returned matcher of type %d; " - "expected: %d", golden_data[i].expr, M(m)->type, - golden_data[i].expected); - - sdb_object_deref(SDB_OBJ(m)); - } -} -END_TEST - -Suite * -fe_parser_suite(void) -{ - Suite *s = suite_create("frontend::parser"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_parse); - tcase_add_test(tc, test_parse_matcher); - suite_add_tcase(s, tc); - - return s; -} /* util_parser_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/frontend/sock_test.c b/t/frontend/sock_test.c deleted file mode 100644 index 55f1a0c..0000000 --- a/t/frontend/sock_test.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SysDB - t/frontend/sock_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "frontend/sock.h" -#include "libsysdb_test.h" - -#include - -#include - -#include -#include - -#include - -#include - -#include -#include -#include - -/* - * private variables - */ - -static sdb_fe_socket_t *sock; - -static void -setup(void) -{ - sock = sdb_fe_sock_create(); - fail_unless(sock != NULL, - "sdb_fe_sock_create() = NULL; expected frontend sock object"); -} /* setup */ - -static void -teardown(void) -{ - sdb_fe_sock_destroy(sock); - sock = NULL; -} /* teardown */ - -static void -sock_listen(char *tmp_file) -{ - char sock_addr[strlen("unix:") + L_tmpnam + 1]; - char *filename; - - int check; - - filename = tmpnam(tmp_file); - fail_unless(filename != NULL, - "INTERNAL ERROR: tmpnam() = NULL; expected: a string"); - - sprintf(sock_addr, "unix:%s", tmp_file); - check = sdb_fe_sock_add_listener(sock, sock_addr); - fail_unless(check == 0, - "sdb_fe_sock_add_listener(%s) = %i; expected: 0", - sock_addr, check); -} /* conn */ - -/* - * parallel testing - */ - -static void * -sock_handler(void *data) -{ - sdb_fe_loop_t *loop = data; - int check; - - check = sdb_fe_sock_listen_and_serve(sock, loop); - fail_unless(check == 0, - "sdb_fe_sock_listen_and_serve() = %i; " - "expected: 0 (after adding listener)", check); - return NULL; -} /* sock_handler */ - -/* - * tests - */ - -START_TEST(test_listen_and_serve) -{ - sdb_fe_loop_t loop = SDB_FE_LOOP_INIT; - - char tmp_file[L_tmpnam]; - int check; - - pthread_t thr; - - int sock_fd; - struct sockaddr_un sa; - - check = sdb_fe_sock_listen_and_serve(sock, &loop); - fail_unless(check < 0, - "sdb_fe_sock_listen_and_serve() = %i; " - "expected: <0 (before adding listeners)", check); - - sock_listen(tmp_file); - - loop.do_loop = 1; - check = pthread_create(&thr, /* attr = */ NULL, sock_handler, &loop); - fail_unless(check == 0, - "INTERNAL ERROR: pthread_create() = %i; expected: 0", check); - - sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); - fail_unless(sock_fd >= 0, - "INTERNAL ERROR: socket() = %d; expected: >= 0", sock_fd); - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, tmp_file, sizeof(sa.sun_path)); - - /* wait for socket to become available */ - errno = ECONNREFUSED; - while (errno == ECONNREFUSED) { - check = connect(sock_fd, (struct sockaddr *)&sa, sizeof(sa)); - if (! check) - break; - - fail_unless(errno == ECONNREFUSED, - "INTERNAL ERROR: connect() = %d [errno=%d]; expected: 0", - check, errno); - } - - close(sock_fd); - - loop.do_loop = 0; - pthread_join(thr, NULL); - - fail_unless(access(tmp_file, F_OK), - "sdb_fe_sock_listen_and_serve() did not clean up " - "socket %s", tmp_file); - - /* should do nothing and not report errors */ - check = sdb_fe_sock_listen_and_serve(sock, &loop); - fail_unless(check == 0, - "sdb_fe_sock_listen_and_serve() = %i; " - "expected: <0 (do_loop == 0)", check); - fail_unless(access(tmp_file, F_OK), - "sdb_fe_sock_listen_and_serve() recreated socket " - "(do_loop == 0)"); -} -END_TEST - -Suite * -fe_sock_suite(void) -{ - Suite *s = suite_create("frontend::sock"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, setup, teardown); - tcase_add_test(tc, test_listen_and_serve); - suite_add_tcase(s, tc); - - return s; -} /* util_unixsock_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/libsysdb_net_test.c b/t/libsysdb_net_test.c deleted file mode 100644 index 85ec83c..0000000 --- a/t/libsysdb_net_test.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SysDB - t/libsysdb_net_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * testing component involving networking operations - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "libsysdb_test.h" - -#include -#include -#include - -int -main(void) -{ - int failed = 0; - size_t i; - - suite_creator_t creators[] = { -#ifdef HAVE_FOPENCOOKIE - { util_unixsock_suite, NULL }, -#else - { NULL, "Skipping util::unixsock; missing fopencookie" }, -#endif /* HAVE_FOPENCOOKIE */ - }; - - putenv("TZ=UTC"); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(creators); ++i) { - SRunner *sr; - Suite *s; - - if (creators[i].msg) - printf("%s\n", creators[i].msg); - - if (!creators[i].creator) - continue; - - s = creators[i].creator(); - sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - failed += srunner_ntests_failed(sr); - srunner_free(sr); - } - - return failed; -} /* main */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/libsysdb_test.c b/t/libsysdb_test.c deleted file mode 100644 index 96bb907..0000000 --- a/t/libsysdb_test.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SysDB - t/libsysdb_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "libsysdb_test.h" - -#include -#include -#include - -int -main(void) -{ - int failed = 0; - size_t i; - - suite_creator_t creators[] = { - { core_data_suite, NULL }, - { core_object_suite, NULL }, - { core_store_suite, NULL }, - { core_store_lookup_suite, NULL }, - { core_time_suite, NULL }, - { fe_conn_suite, NULL }, - { fe_parser_suite, NULL }, - { fe_sock_suite, NULL }, - { util_channel_suite, NULL }, - { util_dbi_suite, NULL }, - { util_llist_suite, NULL }, - { util_strbuf_suite, NULL }, - }; - - putenv("TZ=UTC"); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(creators); ++i) { - SRunner *sr; - Suite *s; - - if (creators[i].msg) - printf("%s\n", creators[i].msg); - - if (!creators[i].creator) - continue; - - s = creators[i].creator(); - sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - failed += srunner_ntests_failed(sr); - srunner_free(sr); - } - - return failed; -} /* main */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h deleted file mode 100644 index 8d98479..0000000 --- a/t/libsysdb_test.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SysDB - t/libsysdb_test.h - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef T_LIBSYSDB_H -#define T_LIBSYSDB_H 1 - -#include "sysdb.h" -#include "core/object.h" - -#include "libsysdb_testutils.h" - -#include -#include - -/* - * private testing helpers - */ - -/* static string object: - * Any such object may is of type sdb_object_t but may never be destroyed. */ -#define SSTRING_OBJ(name) { \ - /* type = */ { sizeof(sdb_object_t), NULL, NULL }, \ - /* ref_cnt = */ 1, /* name = */ (name) } - -/* - * test-related data-types - */ - -typedef struct { - Suite *(*creator)(void); - const char *msg; -} suite_creator_t; - -/* - * test suites - */ - -/* t/core/data_test */ -Suite * -core_data_suite(void); - -/* t/core/object_test */ -Suite * -core_object_suite(void); - -/* t/core/store_test */ -Suite * -core_store_suite(void); - -/* t/core/store_lookup_test */ -Suite * -core_store_lookup_suite(void); - -/* t/core/time_test */ -Suite * -core_time_suite(void); - -/* t/frontend/connection_test */ -Suite * -fe_conn_suite(void); - -/* t/frontend/parser_test */ -Suite * -fe_parser_suite(void); - -/* t/frontend/sock_test */ -Suite * -fe_sock_suite(void); - -/* t/utils/channel_test */ -Suite * -util_channel_suite(void); - -/* t/utils/dbi_test */ -Suite * -util_dbi_suite(void); - -/* t/utils/llist_test */ -Suite * -util_llist_suite(void); - -/* t/utils/strbuf_test */ -Suite * -util_strbuf_suite(void); - -/* t/utils/unixsock_test */ -Suite * -util_unixsock_suite(void); - -#endif /* T_LIBSYSDB_H */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/libsysdb_testutils.c b/t/libsysdb_testutils.c deleted file mode 100644 index 964afdb..0000000 --- a/t/libsysdb_testutils.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SysDB - t/libsysdb_testutils.c - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "libsysdb_testutils.h" - -#include -#include -#include - -int -sdb_regmatches(const char *regex, const char *string) -{ - regex_t reg; - int status; - - status = regcomp(®, regex, REG_EXTENDED | REG_NOSUB); - if (status) - return status; - - status = regexec(®, string, /* matches = */ 0, NULL, /* flags = */ 0); - regfree(®); - return status; -} /* sdb_regmatches */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/libsysdb_testutils.h b/t/libsysdb_testutils.h deleted file mode 100644 index 3f828a9..0000000 --- a/t/libsysdb_testutils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SysDB - t/libsysdb_testutils.h - * Copyright (C) 2014 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Utility functions for test suites. - */ - -#ifndef T_LIBSYSDB_UTILS_H -#define T_LIBSYSDB_UTILS_H 1 - -/* - * sdb_regmatches: - * Check if a regex matches a string. - * - * Returns: - * - 0 if the regex matches - * - a non-zero error value else (see regcomp(3) for details) - */ -int -sdb_regmatches(const char *regex, const char *string); - -#endif /* T_LIBSYSDB_UTILS_H */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c new file mode 100644 index 0000000..432bd75 --- /dev/null +++ b/t/unit/core/data_test.c @@ -0,0 +1,201 @@ +/* + * SysDB - t/unit/core/data_test.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "core/data.h" +#include "libsysdb_test.h" + +#include + +START_TEST(test_data) +{ + sdb_data_t d1, d2; + int check; + + d2.type = SDB_TYPE_INTEGER; + d2.data.integer = 4711; + check = sdb_data_copy(&d1, &d2); + fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); + fail_unless(d1.type == d2.type, + "sdb_data_copy() didn't copy type; got: %i; expected: %i", + d1.type, d2.type); + fail_unless(d1.data.integer == d2.data.integer, + "sdb_data_copy() didn't copy integer data: got: %d; expected: %d", + d1.data.integer, d2.data.integer); + + d2.type = SDB_TYPE_DECIMAL; + d2.data.decimal = 47.11; + check = sdb_data_copy(&d1, &d2); + fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); + fail_unless(d1.type == d2.type, + "sdb_data_copy() didn't copy type; got: %i; expected: %i", + d1.type, d2.type); + fail_unless(d1.data.decimal == d2.data.decimal, + "sdb_data_copy() didn't copy decimal data: got: %f; expected: %f", + d1.data.decimal, d2.data.decimal); + + d2.type = SDB_TYPE_STRING; + d2.data.string = "some string"; + check = sdb_data_copy(&d1, &d2); + fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); + fail_unless(d1.type == d2.type, + "sdb_data_copy() didn't copy type; got: %i; expected: %i", + d1.type, d2.type); + fail_unless(!strcmp(d1.data.string, d2.data.string), + "sdb_data_copy() didn't copy string data: got: %s; expected: %s", + d1.data.string, d2.data.string); + + sdb_data_free_datum(&d1); + fail_unless(d1.data.string == NULL, + "sdb_data_free_datum() didn't free string data"); + + d2.type = SDB_TYPE_DATETIME; + d2.data.datetime = 4711; + check = sdb_data_copy(&d1, &d2); + fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); + fail_unless(d1.type == d2.type, + "sdb_data_copy() didn't copy type; got: %i; expected: %i", + d1.type, d2.type); + fail_unless(d1.data.datetime == d2.data.datetime, + "sdb_data_copy() didn't copy datetime data: got: %d; expected: %d", + d1.data.datetime, d2.data.datetime); + + d2.type = SDB_TYPE_BINARY; + d2.data.binary.datum = (unsigned char *)"some string"; + d2.data.binary.length = strlen((const char *)d2.data.binary.datum); + check = sdb_data_copy(&d1, &d2); + fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check); + fail_unless(d1.type == d2.type, + "sdb_data_copy() didn't copy type; got: %i; expected: %i", + d1.type, d2.type); + fail_unless(d1.data.binary.length == d2.data.binary.length, + "sdb_data_copy() didn't copy length; got: %d; expected: 5d", + d1.data.binary.length, d2.data.binary.length); + fail_unless(!memcmp(d1.data.binary.datum, d2.data.binary.datum, + d2.data.binary.length), + "sdb_data_copy() didn't copy binary data: got: %s; expected: %s", + d1.data.string, d2.data.string); + + sdb_data_free_datum(&d1); + fail_unless(d1.data.binary.length == 0, + "sdb_data_free_datum() didn't reset binary datum length"); + fail_unless(d1.data.binary.datum == NULL, + "sdb_data_free_datum() didn't free binary datum"); +} +END_TEST + +START_TEST(test_format) +{ + struct { + sdb_data_t datum; + const char *expected; + } golden_data[] = { + { + { SDB_TYPE_INTEGER, { .integer = 4711 } }, + "4711", + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, + "0x1p+16", + }, + { + { SDB_TYPE_STRING, { .string = NULL } }, + "\"NULL\"", + }, + { + { SDB_TYPE_STRING, { .string = "this is a test" } }, + "\"this is a test\"", + }, + { + { SDB_TYPE_STRING, { .string = "special \\ \" characters" } }, + "\"special \\\\ \\\" characters\"", + }, + { + { SDB_TYPE_DATETIME, { .datetime= 471147114711471100 } }, + "\"1984-12-06 02:11:54 +0000\"", + }, + { + { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + "\"\"", + }, + { + { + SDB_TYPE_BINARY, + { .binary = { 12, (unsigned char *)"binary\0crap\x42" } }, + }, + "\"\\x62\\x69\\x6e\\x61\\x72\\x79\\x0\\x63\\x72\\x61\\x70\\x42\"", + }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_data_t *datum = &golden_data[i].datum; + char buf[sdb_data_strlen(datum) + 2]; + int check; + + memset(buf, (int)'A', sizeof(buf)); + + check = sdb_data_format(datum, buf, sizeof(buf) - 1, + SDB_DOUBLE_QUOTED); + fail_unless(check > 0, + "sdb_data_format(type=%s) = %d; expected: >0", + SDB_TYPE_TO_STRING(datum->type), check); + fail_unless(! strcmp(buf, golden_data[i].expected), + "sdb_data_format(type=%s) used wrong format: %s; expected: %s", + SDB_TYPE_TO_STRING(datum->type), buf, golden_data[i].expected); + + fail_unless((size_t)check <= sizeof(buf) - 2, + "sdb_data_format(type=%s) wrote %d bytes; " + "expected <= %zu based on sdb_data_strlen()", + SDB_TYPE_TO_STRING(datum->type), check, sizeof(buf) - 2); + + fail_unless(buf[sizeof(buf) - 2] == '\0', + "sdb_data_format(type=%s) did not nul-terminate the buffer", + SDB_TYPE_TO_STRING(datum->type)); + fail_unless(buf[sizeof(buf) - 1] == 'A', + "sdb_data_format(type=%s) wrote past the end of the buffer", + SDB_TYPE_TO_STRING(datum->type)); + } +} +END_TEST + +Suite * +core_data_suite(void) +{ + Suite *s = suite_create("core::data"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_data); + tcase_add_test(tc, test_format); + suite_add_tcase(s, tc); + + return s; +} /* core_data_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/core/object_test.c b/t/unit/core/object_test.c new file mode 100644 index 0000000..dec6d41 --- /dev/null +++ b/t/unit/core/object_test.c @@ -0,0 +1,340 @@ +/* + * SysDB - t/unit/core/object_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "core/object.h" +#include "libsysdb_test.h" + +#include + +/* + * private data types + */ + +static int init_noop_called = 0; +static int init_noop_retval = 0; +static int +obj_init_noop(sdb_object_t *obj, va_list __attribute__((unused)) ap) +{ + ++init_noop_called; + fail_unless(obj != NULL, "obj init function: received obj == NULL"); + return init_noop_retval; +} /* obj_init_noop */ + +static int destroy_noop_called = 0; +static void +obj_destroy_noop(sdb_object_t *obj) +{ + ++destroy_noop_called; + fail_unless(obj != NULL, "obj destroy function: received obj == NULL"); +} /* obj_destroy_noop */ + +struct noop { + sdb_object_t super; + int data; +}; +static sdb_type_t noop_type = { + /* size = */ sizeof(struct noop), + /* init = */ obj_init_noop, + /* destroy = */ obj_destroy_noop, +}; + +static void *wrapped = (void *)0x42; + +static int destroy_wrapper_called = 0; +static void +wrapper_destroy(void *obj) +{ + ++destroy_wrapper_called; + fail_unless(obj == wrapped, + "wrapper_destroy received unexpected obj %p; expected: %p", + obj, wrapped); +} /* wrapper_destroy */ + +START_TEST(test_obj_create) +{ + sdb_object_t *obj; + sdb_type_t test_type = noop_type; + + const char *name = "test-object"; + + init_noop_called = 0; + init_noop_retval = 0; + destroy_noop_called = 0; + obj = sdb_object_create(name, test_type); + fail_unless(obj != NULL, + "sdb_object_create() = NULL; expected: a new object"); + fail_unless(obj->type.size == test_type.size, + "after sdb_object_create(): type size mismatch; got: %zu; " + "expected: %zu", obj->type.size, test_type.size); + fail_unless(obj->type.init == obj_init_noop, + "after sdb_object_create(): type init = %p; exptected: %p", + obj->type.init, obj_init_noop); + fail_unless(obj->type.destroy == obj_destroy_noop, + "after sdb_object_create(): type destroy = %p; exptected: %p", + obj->type.destroy, obj_destroy_noop); + fail_unless(obj->ref_cnt == 1, + "after sdb_object_create(): obj->ref_cnt = %d; expected: 1", + obj->ref_cnt); + fail_unless(!strcmp(obj->name, "test-object"), + "after sdb_object_create(): obj->name = '%s'; expected: '%s'", + obj->name, name); + fail_unless(obj->name != name, + "after sdb_object_create(): obj->name was not strdup()'ed"); + + fail_unless(init_noop_called == 1, + "sdb_object_create() did not call object's init function"); + fail_unless(destroy_noop_called == 0, + "sdb_object_create() called object's destroy function"); + fail_unless(((struct noop *)obj)->data == 0, + "sdb_object_create() did not initialize data to zero"); + + sdb_object_deref(obj); + fail_unless(destroy_noop_called == 1, + "sdb_object_deref() did not call object's destroy function"); + + init_noop_called = 0; + init_noop_retval = -1; + destroy_noop_called = 0; + obj = sdb_object_create(name, test_type); + fail_unless(obj == NULL, + "sdb_object_create() = %p; expected NULL (init returned -1)", + obj); + fail_unless(init_noop_called == 1, + "sdb_object_create() did not call object's init function"); + fail_unless(destroy_noop_called == 1, + "sdb_object_create() did not call object's destroy function " + "after init failure"); + + test_type.size = 1; + init_noop_called = 0; + init_noop_retval = 0; + destroy_noop_called = 0; + obj = sdb_object_create(name, test_type); + fail_unless(obj == NULL, + "sdb_object_create() = %p; expected NULL (type's size too small)", + obj); + fail_unless(init_noop_called == 0, + "sdb_object_create() called object's init function " + "when size was too small"); + fail_unless(destroy_noop_called == 0, + "sdb_object_create() called object's destroy function " + "when size was too small"); + + test_type.size = sizeof(struct noop); + init_noop_retval = 0; + test_type.init = NULL; + obj = sdb_object_create(name, test_type); + fail_unless(obj != NULL, + "sdb_object_create() fails without init callback"); + sdb_object_deref(obj); + + test_type.destroy = NULL; + obj = sdb_object_create(name, test_type); + fail_unless(obj != NULL, + "sdb_object_create() fails without destroy callback"); + sdb_object_deref(obj); + + init_noop_called = 0; + obj = sdb_object_create_simple(name, sizeof(struct noop), NULL); + fail_unless(obj != NULL, + "sdb_object_create_simple() = NULL; expected: "); + fail_unless(obj->type.size == sizeof(struct noop), + "sdb_object_create_simple() created object of size %zu; " + "expected: %zu", obj->type.size, sizeof(struct noop)); + fail_unless(obj->type.init == NULL, + "sdb_object_create_simple() did not set init=NULL"); + fail_unless(obj->type.destroy == NULL, + "sdb_object_create_simple() did not set destroy=NULL"); + fail_unless(init_noop_called == 0, + "sdb_object_create_simple() unexpectedly called noop's init"); + sdb_object_deref(obj); + + obj = sdb_object_create_T(NULL, struct noop); + fail_unless(obj != NULL, + "sdb_object_create_simple() = NULL; expected: "); + fail_unless(obj->type.size == sizeof(struct noop), + "sdb_object_create_simple() created object of size %zu; " + "expected: %zu", obj->type.size, sizeof(struct noop)); + fail_unless(obj->type.init == NULL, + "sdb_object_create_simple() did not set init=NULL"); + fail_unless(obj->type.destroy == NULL, + "sdb_object_create_simple() did not set destroy=NULL"); + fail_unless(init_noop_called == 0, + "sdb_object_create_simple() unexpectedly called noop's init"); + sdb_object_deref(obj); +} +END_TEST + +START_TEST(test_obj_wrapper) +{ + sdb_object_t *obj; + const char *name = "wrapped-object"; + + destroy_wrapper_called = 0; + obj = sdb_object_create_wrapper(name, wrapped, wrapper_destroy); + fail_unless(obj != NULL, + "sdb_object_create_wrapper() = NULL; expected: wrapper object"); + fail_unless(obj->ref_cnt == 1, + "after sdb_object_create_wrapper(); obj->ref_cnt = %d; " + "expected: 1", obj->ref_cnt); + fail_unless(!strcmp(obj->name, name), + "after sdb_object_create_wrapper(); obj->name = %s; expected: %s", + obj->name, name); + fail_unless(obj->name != name, + "sdb_object_create_wrapper() did not copy object name"); + fail_unless(SDB_OBJ_WRAPPER(obj)->data == wrapped, + "wrapped object wraps unexpected data %p; expected: %p", + SDB_OBJ_WRAPPER(obj)->data, wrapped); + + fail_unless(destroy_wrapper_called == 0, + "sdb_object_create_wrapper() called object's destructor"); + + sdb_object_deref(obj); + fail_unless(destroy_wrapper_called == 1, + "sdb_object_deref() did not call wrapped object's destructor"); +} +END_TEST + +START_TEST(test_obj_ref) +{ + sdb_object_t *obj; + sdb_type_t test_type = noop_type; + + init_noop_called = 0; + init_noop_retval = 0; + destroy_noop_called = 0; + + obj = sdb_object_create("test-object", test_type); + fail_unless(obj != NULL, + "sdb_object_create() = NULL; expected: valid object"); + + sdb_object_ref(obj); + fail_unless(obj->ref_cnt == 2, + "after db_object_ref(): obj->ref_cnt = %d; expected: 2", + obj->ref_cnt); + + sdb_object_ref(obj); + fail_unless(obj->ref_cnt == 3, + "after db_object_ref(): obj->ref_cnt = %d; expected: 3", + obj->ref_cnt); + + obj->ref_cnt = 42; + sdb_object_ref(obj); + fail_unless(obj->ref_cnt == 43, + "after db_object_ref(): obj->ref_cnt = %d; expected: 43", + obj->ref_cnt); + + fail_unless(init_noop_called == 1, + "after some sdb_object_ref(); object's init called %d times; " + "expected: 1", init_noop_called); + fail_unless(destroy_noop_called == 0, + "after some sdb_object_ref(); object's destroy called %d time%s; " + "expected: 0", destroy_noop_called == 1 ? "" : "2", + destroy_noop_called); + + sdb_object_deref(obj); + fail_unless(obj->ref_cnt == 42, + "after db_object_deref(): obj->ref_cnt = %d; expected: 42", + obj->ref_cnt); + + obj->ref_cnt = 23; + sdb_object_deref(obj); + fail_unless(obj->ref_cnt == 22, + "after db_object_deref(): obj->ref_cnt = %d; expected: 22", + obj->ref_cnt); + + fail_unless(init_noop_called == 1, + "after some sdb_object_{de,}ref(); object's init called %d times; " + "expected: 1", init_noop_called); + fail_unless(destroy_noop_called == 0, + "after some sdb_object_{de,}ref(); object's destroy called " + "%d time%s; expected: 0", destroy_noop_called == 1 ? "" : "2", + destroy_noop_called); + + /* test_obj_create already checks the ref_cnt == 1 case */ + obj->ref_cnt = 0; + sdb_object_deref(obj); + fail_unless(init_noop_called == 1, + "after some sdb_object_{de,}ref(); object's init called %d times; " + "expected: 1", init_noop_called); + fail_unless(destroy_noop_called == 1, + "after some sdb_object_{de,}ref(); object's destroy called " + "%d times; expected: 1", destroy_noop_called); + + /* this should work */ + sdb_object_deref(NULL); +} +END_TEST + +START_TEST(test_obj_cmp) +{ + sdb_object_t *obj1, *obj2, *obj3, *obj4; + int status; + + obj1 = sdb_object_create("a", noop_type); + obj2 = sdb_object_create("b", noop_type); + obj3 = sdb_object_create("B", noop_type); + obj4 = sdb_object_create("c", noop_type); + + status = sdb_object_cmp_by_name(obj1, obj2); + fail_unless(status == -1, + "sdb_object_cmp_by_name('a', 'b') = %d; expected: -1", status); + status = sdb_object_cmp_by_name(obj2, obj3); + fail_unless(status == 0, + "sdb_object_cmp_by_name('b', 'B') = %d; expected: 0", status); + status = sdb_object_cmp_by_name(obj4, obj3); + fail_unless(status == 1, + "sdb_object_cmp_by_name('c', 'B') = %d; expected: 1", status); + status = sdb_object_cmp_by_name(obj1, obj1); + fail_unless(status == 0, + "sdb_object_cmp_by_name('a', 'a') = %d; expected: 0", status); + + sdb_object_deref(obj1); + sdb_object_deref(obj2); + sdb_object_deref(obj3); + sdb_object_deref(obj4); +} +END_TEST + +Suite * +core_object_suite(void) +{ + Suite *s = suite_create("core::object"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_obj_create); + tcase_add_test(tc, test_obj_wrapper); + tcase_add_test(tc, test_obj_ref); + tcase_add_test(tc, test_obj_cmp); + suite_add_tcase(s, tc); + + return s; +} /* core_object_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/core/store_lookup_test.c b/t/unit/core/store_lookup_test.c new file mode 100644 index 0000000..5631519 --- /dev/null +++ b/t/unit/core/store_lookup_test.c @@ -0,0 +1,535 @@ +/* + * SysDB - t/unit/core/store_lookup_test.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "core/store.h" +#include "core/store-private.h" +#include "frontend/parser.h" +#include "libsysdb_test.h" + +#include +#include + +static void +populate(void) +{ + const char *hosts[] = { "a", "b", "c" }; + + struct { + const char *host; + const char *service; + } services[] = { + { "a", "s1" }, + { "a", "s2" }, + { "b", "s1" }, + { "b", "s3" }, + }; + + struct { + const char *host; + const char *name; + sdb_data_t value; + } attrs[] = { + { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) { + int status = sdb_store_host(hosts[i], 1); + fail_unless(status == 0, + "sdb_store_host(%s, 1) = %d; expected: 0", + hosts[i], status); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) { + int status = sdb_store_service(services[i].host, + services[i].service, 1); + fail_unless(status == 0, + "sdb_store_service(%s, %s, 1) = %d; expected: 0", + services[i].host, services[i].service, status); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) { + int status = sdb_store_attribute(attrs[i].host, + attrs[i].name, &attrs[i].value, 1); + fail_unless(status == 0, + "sdb_store_attribute(%s, %s, , 1) = %d; expected: 0", + attrs[i].host, attrs[i].name, status); + } +} /* populate */ + +START_TEST(test_store_match) +{ + sdb_store_base_t *obj; + + struct { + const char *hostname; + const char *hostname_re; + + const char *service_name; + const char *service_name_re; + + const char *attr_name; + const char *attr_name_re; + const char *attr_value; + const char *attr_value_re; + + int expected; + } golden_data[] = { + { + /* host */ NULL, NULL, + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "a", NULL, + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "b", NULL, + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ NULL, "^a$", + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ NULL, "^b$", + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "a", "^b$", + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "b", "^a$", + /* svc */ NULL, NULL, + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", NULL, + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ NULL, "^s1$", + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ NULL, NULL, NULL, NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "x1", NULL, + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ NULL, "x", + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ "x1", "x", + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "x", + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ "x1", "s", + /* attr */ NULL, NULL, NULL, NULL, 0 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ "k1", NULL, NULL, NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ NULL, "^k", NULL, NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ NULL, NULL, "v1", NULL, 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ NULL, NULL, NULL, "^v1$", 1 + }, + { + /* host */ "a", "^a$", + /* svc */ "s1", "^s1$", + /* attr */ "k1", "1", "v1", "1", 1 + }, + }; + + size_t i; + + obj = sdb_store_get_host("a"); + fail_unless(obj != NULL, + "sdb_store_get_host(a) = NULL; expected: "); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_store_matcher_t *h, *s, *a, *n; + int status; + + s = sdb_store_service_matcher(golden_data[i].service_name, + golden_data[i].service_name_re, NULL); + fail_unless(s != NULL, + "sdb_store_service_matcher() = NULL; expected: "); + + a = sdb_store_attr_matcher(golden_data[i].attr_name, + golden_data[i].attr_name_re, golden_data[i].attr_value, + golden_data[i].attr_value_re); + fail_unless(a != NULL, + "sdb_store_attr_matcher() = NULL; expected: "); + + h = sdb_store_host_matcher(golden_data[i].hostname, + golden_data[i].hostname_re, s, a); + fail_unless(h != NULL, + "sdb_store_host_matcher() = NULL: expected: "); + /* pass ownership to the host matcher */ + sdb_object_deref(SDB_OBJ(s)); + sdb_object_deref(SDB_OBJ(a)); + + status = sdb_store_matcher_matches(h, obj); + fail_unless(status == golden_data[i].expected, + "sdb_store_matcher_matches({{%s, %s},{%s, %s}," + "{%s, %s, %s, %s}}, ) = %d; expected: %d", + golden_data[i].hostname, golden_data[i].hostname_re, + golden_data[i].service_name, golden_data[i].service_name_re, + golden_data[i].attr_name, golden_data[i].attr_name_re, + golden_data[i].attr_value, golden_data[i].attr_value_re, + status, golden_data[i].expected); + + n = sdb_store_inv_matcher(h); + fail_unless(n != NULL, + "sdb_store_inv_matcher() = NULL; expected: "); + sdb_object_deref(SDB_OBJ(h)); + + /* now match the inverted set of objects */ + status = sdb_store_matcher_matches(n, obj); + fail_unless(status == !golden_data[i].expected, + "sdb_store_matcher_matches(NOT{{%s, %s},{%s, %s}," + "{%s, %s, %s, %s}}, ) = %d; expected: %d", + golden_data[i].hostname, golden_data[i].hostname_re, + golden_data[i].service_name, golden_data[i].service_name_re, + golden_data[i].attr_name, golden_data[i].attr_name_re, + golden_data[i].attr_value, golden_data[i].attr_value_re, + status, !golden_data[i].expected); + + sdb_object_deref(SDB_OBJ(n)); + } + + sdb_object_deref(SDB_OBJ(obj)); +} +END_TEST + +START_TEST(test_store_match_op) +{ + sdb_store_base_t *obj; + + sdb_store_matcher_t *always = sdb_store_host_matcher(NULL, NULL, NULL, NULL); + sdb_store_matcher_t *never = sdb_store_host_matcher("a", "b", NULL, NULL); + + struct { + const char *op; + sdb_store_matcher_t *left; + sdb_store_matcher_t *right; + int expected; + } golden_data[] = { + { "OR", always, always, 1 }, + { "OR", always, never, 1 }, + { "OR", never, always, 1 }, + { "OR", never, never, 0 }, + { "AND", always, always, 1 }, + { "AND", always, never, 0 }, + { "AND", never, always, 0 }, + { "AND", never, never, 0 }, + }; + + int status; + size_t i; + + obj = sdb_store_get_host("a"); + + status = sdb_store_matcher_matches(always, obj); + fail_unless(status == 1, + "INTERNAL ERROR: 'always' did not match host"); + status = sdb_store_matcher_matches(never, obj); + fail_unless(status == 0, + "INTERNAL ERROR: 'never' matches host"); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_store_matcher_t *m; + + if (! strcmp(golden_data[i].op, "OR")) + m = sdb_store_dis_matcher(golden_data[i].left, + golden_data[i].right); + else if (! strcmp(golden_data[i].op, "AND")) + m = sdb_store_con_matcher(golden_data[i].left, + golden_data[i].right); + else { + fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op); + continue; + } + +#define TO_NAME(v) (((v) == always) ? "always" \ + : ((v) == never) ? "never" : "") + + status = sdb_store_matcher_matches(m, obj); + fail_unless(status == golden_data[i].expected, + "%s(%s, %s) = %d; expected: %d", golden_data[i].op, + TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right), + status, golden_data[i].expected); + +#undef TO_NAME + + sdb_object_deref(SDB_OBJ(m)); + } + + sdb_object_deref(SDB_OBJ(always)); + sdb_object_deref(SDB_OBJ(never)); + + sdb_object_deref(SDB_OBJ(obj)); +} +END_TEST + +START_TEST(test_parse_cmp) +{ + sdb_store_matcher_t *check; + + size_t i; + + struct { + const char *obj_type; + const char *attr; + const char *op; + const char *value; + int expected; + } golden_data[] = { + { "host", "name", "=", "hostname", MATCHER_HOST }, + { "host", "name", "!=", "hostname", MATCHER_NOT }, + { "host", "name", "=~", "hostname", MATCHER_HOST }, + { "host", "name", "!~", "hostname", MATCHER_NOT }, + { "host", "attr", "=", "hostname", -1 }, + { "host", "attr", "!=", "hostname", -1 }, + { "host", "name", "&^", "hostname", -1 }, + { "service", "name", "=", "srvname", MATCHER_HOST }, + { "service", "name", "!=", "srvname", MATCHER_NOT }, + { "service", "name", "=~", "srvname", MATCHER_HOST }, + { "service", "name", "!~", "srvname", MATCHER_NOT }, + { "service", "attr", "=", "srvname", -1 }, + { "service", "attr", "!=", "srvname", -1 }, + { "service", "name", "&^", "srvname", -1 }, + { "attribute", "name", "=", "attrname", MATCHER_HOST }, + { "attribute", "name", "!=", "attrname", MATCHER_NOT }, + { "attribute", "name", "=~", "attrname", MATCHER_HOST }, + { "attribute", "name", "!~", "attrname", MATCHER_NOT }, + { "attribute", "attr", "=", "attrname", MATCHER_HOST }, + { "attribute", "attr", "!=", "attrname", MATCHER_NOT }, + { "attribute", "attr", "=~", "attrname", MATCHER_HOST }, + { "attribute", "attr", "!~", "attrname", MATCHER_NOT }, + { "attribute", "attr", "&^", "attrname", -1 }, + }; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + check = sdb_store_matcher_parse_cmp(golden_data[i].obj_type, + golden_data[i].attr, golden_data[i].op, golden_data[i].value); + + if (golden_data[i].expected == -1) { + fail_unless(check == NULL, + "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; " + "expected: NULL", golden_data[i].obj_type, + golden_data[i].attr, golden_data[i].op, + golden_data[i].value, check); + continue; + } + + fail_unless(check != NULL, + "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; " + "expected: NULL", golden_data[i].obj_type, + golden_data[i].attr, golden_data[i].op, + golden_data[i].value, check); + fail_unless(M(check)->type == golden_data[i].expected, + "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) returned matcher " + "of type %d; expected: %d", golden_data[i].obj_type, + golden_data[i].attr, golden_data[i].op, golden_data[i].value, + M(check)->type, golden_data[i].expected); + + sdb_object_deref(SDB_OBJ(check)); + } +} +END_TEST + +static int +lookup_cb(sdb_store_base_t *obj, void *user_data) +{ + int *i = user_data; + + fail_unless(obj != NULL, + "sdb_store_lookup callback received NULL obj; expected: " + ""); + fail_unless(i != NULL, + "sdb_store_lookup callback received NULL user_data; " + "expected: "); + + ++(*i); + return 0; +} /* lookup_cb */ + +START_TEST(test_lookup) +{ +#define PTR_RE "0x[0-9a-f]+" + struct { + const char *query; + int expected; + const char *tostring_re; + } golden_data[] = { + { "host.name = 'a'", 1, + "HOST\\{ NAME\\{ 'a', \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ 'a|b'", 2, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ 'host'", 0, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ '.'", 3, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "service.name = 's1'", 2, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ 's1', \\(nil\\) }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\}" }, + { "service.name =~ 's'", 2, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\}" }, + { "service.name !~ 's'", 1, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\})" }, + { "attribute.name = 'k1'", 1, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.name = 'x'", 0, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.k1 = 'v1'", 1, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.k1 != 'v1'", 2, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " + "\\} \\})" }, + { "attribute.k1 != 'v2'", 3, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v2', \\(nil\\) \\} " + "\\} \\})" }, + { "attribute.name != 'x' " + "AND attribute.y !~ 'x'", 3, + "\\(AND, \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " + "\\} \\}\\), \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'y', \\(nil\\) }, VALUE\\{ NULL, "PTR_RE" \\} " + "\\} \\}\\)\\)" }, + }; + + int check, n; + size_t i; + + n = 0; + check = sdb_store_lookup(NULL, lookup_cb, &n); + fail_unless(check == 0, + "sdb_store_lookup() = %d; expected: 0", check); + fail_unless(n == 3, + "sdb_store_lookup called callback %d times; expected: 3", (int)n); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_store_matcher_t *m; + char buf[4096]; + + m = sdb_fe_parse_matcher(golden_data[i].query, -1); + fail_unless(m != NULL, + "sdb_fe_parse_matcher(%s, -1) = NULL; expected: ", + golden_data[i].query); + fail_unless(sdb_regmatches(golden_data[i].tostring_re, + sdb_store_matcher_tostring(m, buf, sizeof(buf))) == 0, + "sdb_fe_parse_matcher(%s, -1) = %s; expected: %s", + golden_data[i].query, + sdb_store_matcher_tostring(m, buf, sizeof(buf)), + golden_data[i].tostring_re); + + n = 0; + sdb_store_lookup(m, lookup_cb, &n); + fail_unless(n == golden_data[i].expected, + "sdb_store_lookup(matcher{%s}) found %d hosts; expected: %d", + golden_data[i].query, n, golden_data[i].expected); + sdb_object_deref(SDB_OBJ(m)); + } +} +END_TEST + +Suite * +core_store_lookup_suite(void) +{ + Suite *s = suite_create("core::store_lookup"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, populate, sdb_store_clear); + tcase_add_test(tc, test_store_match); + tcase_add_test(tc, test_store_match_op); + tcase_add_test(tc, test_parse_cmp); + tcase_add_test(tc, test_lookup); + suite_add_tcase(s, tc); + + return s; +} /* core_store_lookup_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/core/store_test.c b/t/unit/core/store_test.c new file mode 100644 index 0000000..07651ee --- /dev/null +++ b/t/unit/core/store_test.c @@ -0,0 +1,509 @@ +/* + * SysDB - t/unit/core/store_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "core/store.h" +#include "core/store-private.h" +#include "libsysdb_test.h" + +#include +#include + +static void +populate(void) +{ + sdb_data_t datum; + + sdb_store_host("h1", 1); + sdb_store_host("h2", 1); + + datum.type = SDB_TYPE_STRING; + datum.data.string = "v1"; + sdb_store_attribute("h1", "k1", &datum, 1); + datum.data.string = "v2"; + sdb_store_attribute("h1", "k2", &datum, 1); + datum.data.string = "v3"; + sdb_store_attribute("h1", "k3", &datum, 1); + + sdb_store_service("h2", "s1", 1); + sdb_store_service("h2", "s2", 1); +} /* populate */ + +START_TEST(test_store_host) +{ + struct { + const char *name; + sdb_time_t last_update; + int expected; + } golden_data[] = { + { "a", 2, 0 }, + { "a", 3, 0 }, + { "a", 1, 1 }, + { "b", 2, 0 }, + { "b", 1, 1 }, + { "A", 1, 1 }, /* case-insensitive */ + { "A", 4, 0 }, + }; + + struct { + const char *name; + _Bool has; + } golden_hosts[] = { + { "a", 1 == 1 }, + { "b", 1 == 1 }, + { "c", 0 == 1 }, + { "A", 1 == 1 }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int status; + + status = sdb_store_host(golden_data[i].name, + golden_data[i].last_update); + fail_unless(status == golden_data[i].expected, + "sdb_store_host(%s, %d) = %d; expected: %d", + golden_data[i].name, (int)golden_data[i].last_update, + status, golden_data[i].expected); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { + _Bool has; + + has = sdb_store_has_host(golden_hosts[i].name); + fail_unless(has == golden_hosts[i].has, + "sdb_store_has_host(%s) = %d; expected: %d", + golden_hosts[i].name, has, golden_hosts[i].has); + } +} +END_TEST + +START_TEST(test_store_get_host) +{ + char *golden_hosts[] = { "a", "b", "c" }; + char *unknown_hosts[] = { "x", "y", "z" }; + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { + int status = sdb_store_host(golden_hosts[i], 1); + fail_unless(status >= 0, + "sdb_store_host(%s) = %d; expected: >=0", + golden_hosts[i], status); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) { + sdb_store_base_t *sobj1, *sobj2; + int ref_cnt; + + fail_unless(sdb_store_has_host(golden_hosts[i]), + "sdb_store_has_host(%s) = FALSE; expected: TRUE", + golden_hosts[i]); + + sobj1 = sdb_store_get_host(golden_hosts[i]); + fail_unless(sobj1 != NULL, + "sdb_store_get_host(%s) = NULL; expected: ", + golden_hosts[i]); + ref_cnt = SDB_OBJ(sobj1)->ref_cnt; + + fail_unless(ref_cnt > 1, + "sdb_store_get_host(%s) did not increment ref count: " + "got: %d; expected: >1", golden_hosts[i], ref_cnt); + + sobj2 = sdb_store_get_host(golden_hosts[i]); + fail_unless(sobj2 != NULL, + "sdb_store_get_host(%s) = NULL; expected: ", + golden_hosts[i]); + + fail_unless(sobj1 == sobj2, + "sdb_store_get_host(%s) returned different objects " + "in successive calls", golden_hosts[i]); + fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1, + "sdb_store_get_hosts(%s) did not increment ref count " + "(first call: %d; second call: %d)", + golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt); + + sdb_object_deref(SDB_OBJ(sobj1)); + sdb_object_deref(SDB_OBJ(sobj2)); + } + for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) { + sdb_store_base_t *sobj; + + fail_unless(!sdb_store_has_host(unknown_hosts[i]), + "sdb_store_has_host(%s) = TRUE; expected: FALSE", + unknown_hosts[i]); + + sobj = sdb_store_get_host(unknown_hosts[i]); + fail_unless(!sobj, "sdb_store_get_host(%s) = ; expected: NULL", + unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL"); + } +} +END_TEST + +START_TEST(test_store_attr) +{ + struct { + const char *host; + const char *key; + char *value; + sdb_time_t last_update; + int expected; + } golden_data[] = { + { "k", "k", "v", 1, -1 }, + { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */ + { "l", "k1", "v1", 1, 0 }, + { "l", "k1", "v2", 2, 0 }, + { "l", "k1", "v3", 1, 1 }, + { "l", "k2", "v1", 1, 0 }, + { "m", "k", "v1", 2, 0 }, + { "m", "k", "v2", 1, 1 }, + }; + + size_t i; + + sdb_store_host("l", 1); + sdb_store_host("m", 1); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_data_t datum; + int status; + + /* XXX: test other types as well */ + datum.type = SDB_TYPE_STRING; + datum.data.string = golden_data[i].value; + + status = sdb_store_attribute(golden_data[i].host, + golden_data[i].key, &datum, + golden_data[i].last_update); + fail_unless(status == golden_data[i].expected, + "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d", + golden_data[i].host, golden_data[i].key, golden_data[i].value, + golden_data[i].last_update, status, golden_data[i].expected); + } +} +END_TEST + +START_TEST(test_store_service) +{ + struct { + const char *host; + const char *svc; + sdb_time_t last_update; + int expected; + } golden_data[] = { + { "k", "s", 1, -1 }, + { "k", "s", 1, -1 }, /* retry to ensure the host is not created */ + { "l", "s1", 1, 0 }, + { "l", "s1", 2, 0 }, + { "l", "s1", 1, 1 }, + { "l", "s2", 1, 0 }, + { "m", "s", 2, 0 }, + { "m", "s", 1, 1 }, + }; + + size_t i; + + sdb_store_host("m", 1); + sdb_store_host("l", 1); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int status; + + status = sdb_store_service(golden_data[i].host, + golden_data[i].svc, golden_data[i].last_update); + fail_unless(status == golden_data[i].expected, + "sdb_store_service(%s, %s, %d) = %d; expected: %d", + golden_data[i].host, golden_data[i].svc, + golden_data[i].last_update, status, golden_data[i].expected); + } +} +END_TEST + +static void +verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags) +{ + int pos; + size_t len1, len2; + size_t i; + + len1 = strlen(sdb_strbuf_string(buf)); + len2 = strlen(expected); + + pos = -1; + if (len1 != len2) + pos = (int)(len1 <= len2 ? len1 : len2); + + for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) { + if (sdb_strbuf_string(buf)[i] != expected[i]) { + pos = (int)i; + break; + } + } + + fail_unless(pos == -1, + "sdb_store_tojson(%x) returned unexpected result\n" + " got: %s\n %*s\n expected: %s", + flags, sdb_strbuf_string(buf), pos + 1, "^", expected); +} /* verify_json_output */ + +START_TEST(test_store_tojson) +{ + sdb_strbuf_t *buf; + size_t i; + + struct { + int flags; + const char *expected; + } golden_data[] = { + { 0, "{\"hosts\":[" + "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"attributes\": [" + "{\"name\": \"k1\", \"value\": \"v1\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"k2\", \"value\": \"v2\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"k3\", \"value\": \"v3\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}" + "], " + "\"services\": []}," + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"attributes\": [], " + "\"services\": [" + "{\"name\": \"s1\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"s2\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}" + "]}" + "]}" }, + { SDB_SKIP_SERVICES, + "{\"hosts\":[" + "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"attributes\": [" + "{\"name\": \"k1\", \"value\": \"v1\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"k2\", \"value\": \"v2\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"k3\", \"value\": \"v3\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}" + "]}," + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"attributes\": []}" + "]}" }, + { SDB_SKIP_ATTRIBUTES, + "{\"hosts\":[" + "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"services\": []}," + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\", " + "\"services\": [" + "{\"name\": \"s1\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"s2\", " + "\"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}" + "]}" + "]}" }, + { SDB_SKIP_SERVICES | SDB_SKIP_ATTRIBUTES, + "{\"hosts\":[" + "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}," + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"update_interval\": \"0s\"}" + "]}" }, + }; + + buf = sdb_strbuf_create(0); + fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer"); + populate(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int status; + + sdb_strbuf_clear(buf); + + status = sdb_store_tojson(buf, golden_data[i].flags); + fail_unless(status == 0, + "sdb_store_tojson(%x) = %d; expected: 0", + golden_data[i].flags, status); + + verify_json_output(buf, golden_data[i].expected, golden_data[i].flags); + } + sdb_strbuf_destroy(buf); +} +END_TEST + +START_TEST(test_interval) +{ + sdb_store_base_t *host; + + /* 10 us interval */ + sdb_store_host("host", 10); + sdb_store_host("host", 20); + sdb_store_host("host", 30); + sdb_store_host("host", 40); + + host = sdb_store_get_host("host"); + fail_unless(host != NULL, + "INTERNAL ERROR: store doesn't have host after adding it"); + + fail_unless(host->interval == 10, + "sdb_store_host() did not calculate interval correctly: " + "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 10); + + /* multiple updates for the same timestamp don't modify the interval */ + sdb_store_host("host", 40); + sdb_store_host("host", 40); + sdb_store_host("host", 40); + sdb_store_host("host", 40); + + fail_unless(host->interval == 10, + "sdb_store_host() changed interval when doing multiple updates " + "using the same timestamp; got: %"PRIscTIME"; " + "expected: %"PRIscTIME, host->interval, 10); + + /* multiple updates using an timestamp don't modify the interval */ + sdb_store_host("host", 20); + sdb_store_host("host", 20); + sdb_store_host("host", 20); + sdb_store_host("host", 20); + + fail_unless(host->interval == 10, + "sdb_store_host() changed interval when doing multiple updates " + "using an old timestamp; got: %"PRIscTIME"; expected: %"PRIscTIME, + host->interval, 10); + + /* new interval: 20 us */ + sdb_store_host("host", 60); + fail_unless(host->interval == 11, + "sdb_store_host() did not calculate interval correctly: " + "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 11); + + /* new interval: 40 us */ + sdb_store_host("host", 100); + fail_unless(host->interval == 13, + "sdb_store_host() did not calculate interval correctly: " + "got: %"PRIscTIME"; expected: %"PRIscTIME, host->interval, 11); + + sdb_object_deref(SDB_OBJ(host)); +} +END_TEST + +static int +iter_incr(sdb_store_base_t *obj, void *user_data) +{ + intptr_t *i = user_data; + + fail_unless(obj != NULL, + "sdb_store_iterate callback received NULL obj; expected: " + ""); + fail_unless(i != NULL, + "sdb_store_iterate callback received NULL user_data; " + "expected: "); + + ++(*i); + return 0; +} /* iter_incr */ + +static int +iter_error(sdb_store_base_t *obj, void *user_data) +{ + intptr_t *i = user_data; + + fail_unless(obj != NULL, + "sdb_store_iterate callback received NULL obj; expected: " + ""); + fail_unless(i != NULL, + "sdb_store_iterate callback received NULL user_data; " + "expected: "); + + ++(*i); + return -1; +} /* iter_error */ + +START_TEST(test_iterate) +{ + intptr_t i = 0; + int check; + + /* empty store */ + check = sdb_store_iterate(iter_incr, &i); + fail_unless(check == -1, + "sdb_store_iterate(), empty store = %d; expected: -1", check); + fail_unless(i == 0, + "sdb_store_iterate called callback %d times; expected: 0", (int)i); + + populate(); + + check = sdb_store_iterate(iter_incr, &i); + fail_unless(check == 0, + "sdb_store_iterate() = %d; expected: 0", check); + fail_unless(i == 2, + "sdb_store_iterate called callback %d times; expected: 1", (int)i); + + i = 0; + check = sdb_store_iterate(iter_error, &i); + fail_unless(check == -1, + "sdb_store_iterate(), error callback = %d; expected: -1", check); + fail_unless(i == 1, + "sdb_store_iterate called callback %d times " + "(callback returned error); expected: 1", (int)i); +} +END_TEST + +Suite * +core_store_suite(void) +{ + Suite *s = suite_create("core::store"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_store_tojson); + tcase_add_test(tc, test_store_host); + tcase_add_test(tc, test_store_get_host); + tcase_add_test(tc, test_store_attr); + tcase_add_test(tc, test_store_service); + tcase_add_test(tc, test_interval); + tcase_add_test(tc, test_iterate); + tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear); + suite_add_tcase(s, tc); + + return s; +} /* core_store_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/core/time_test.c b/t/unit/core/time_test.c new file mode 100644 index 0000000..2bffbbd --- /dev/null +++ b/t/unit/core/time_test.c @@ -0,0 +1,99 @@ +/* + * SysDB - t/unit/core/time_test.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "core/time.h" +#include "libsysdb_test.h" + +#include + +START_TEST(test_strfinterval) +{ + char buf[1024]; + size_t check; + size_t i; + + struct { + sdb_time_t interval; + const char *expected; + } golden_data[] = { + { 0, "0s" }, + { 4711, ".000004711s" }, + { 1000123400, "1.0001234s" }, + { 47940228000000000L, "1Y6M7D" }, + { SDB_INTERVAL_YEAR, "1Y" }, + { SDB_INTERVAL_MONTH, "1M" }, + { SDB_INTERVAL_DAY, "1D" }, + { SDB_INTERVAL_HOUR, "1h" }, + { SDB_INTERVAL_MINUTE, "1m" }, + { SDB_INTERVAL_SECOND, "1s" }, + { SDB_INTERVAL_YEAR + + SDB_INTERVAL_MONTH + + SDB_INTERVAL_DAY + + SDB_INTERVAL_HOUR + + SDB_INTERVAL_MINUTE + + SDB_INTERVAL_SECOND + + 1234, "1Y1M1D1h1m1.000001234s" }, + }; + + /* this should return the number of bytes which would have been written; + * most notably, it should not segfault ;-) */ + check = sdb_strfinterval(NULL, 0, 4711); /* expected: .000004711s */ + fail_unless(check == 11, + "sdb_strfinterval(NULL, 0, 4711) = %zu; expected: 11", check); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + check = sdb_strfinterval(buf, sizeof(buf), golden_data[i].interval); + fail_unless(check > 0, + "sdb_strfinterval(, , %"PRIscTIME") = %zu; " + "expected: >0", golden_data[i].interval, check); + fail_unless(!strcmp(buf, golden_data[i].expected), + "sdb_strfinterval(, , %"PRIscTIME") did not " + "format interval correctly; got: '%s'; expected: '%s'", + golden_data[i].interval, buf, golden_data[i].expected); + fail_unless(check == strlen(golden_data[i].expected), + "sdb_strfinterval(, , %"PRIscTIME") = %zu; " + "expected: %zu", golden_data[i].interval, check, + strlen(golden_data[i].expected)); + } +} +END_TEST + +Suite * +core_time_suite(void) +{ + Suite *s = suite_create("core::time"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_strfinterval); + suite_add_tcase(s, tc); + + return s; +} /* core_time_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/frontend/connection_test.c b/t/unit/frontend/connection_test.c new file mode 100644 index 0000000..125bb56 --- /dev/null +++ b/t/unit/frontend/connection_test.c @@ -0,0 +1,285 @@ +/* + * SysDB - t/unit/frontend/connection_test.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "frontend/connection.h" +#include "frontend/connection-private.h" +#include "libsysdb_test.h" + +#include "utils/strbuf.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +/* + * private helper functions + */ + +static void +mock_conn_destroy(sdb_conn_t *conn) +{ + if (SDB_OBJ(conn)->name) + free(SDB_OBJ(conn)->name); + sdb_strbuf_destroy(conn->buf); + sdb_strbuf_destroy(conn->errbuf); + if (conn->fd >= 0) + close(conn->fd); + free(conn); +} /* mock_conn_destroy */ + +static sdb_conn_t * +mock_conn_create(void) +{ + sdb_conn_t *conn; + + char tmp_file[] = "connection_test_socket.XXXXXX"; + + conn = calloc(1, sizeof(*conn)); + if (! conn) { + fail("INTERNAL ERROR: failed to allocate connection object"); + return NULL; + } + + SDB_OBJ(conn)->name = strdup("mock_connection"); + SDB_OBJ(conn)->ref_cnt = 1; + + conn->buf = sdb_strbuf_create(0); + conn->errbuf = sdb_strbuf_create(0); + if ((! conn->buf) || (! conn->errbuf)) { + mock_conn_destroy(conn); + fail("INTERNAL ERROR: failed to allocate connection object"); + return NULL; + } + + conn->fd = mkstemp(tmp_file); + if (conn->fd < 0) { + mock_conn_destroy(conn); + fail("INTERNAL ERROR: failed to allocate connection object"); + return NULL; + } + + unlink(tmp_file); + + conn->cmd = CONNECTION_IDLE; + conn->cmd_len = 0; + return conn; +} /* mock_conn_create */ + +static void +mock_conn_rewind(sdb_conn_t *conn) +{ + lseek(conn->fd, 0, SEEK_SET); +} /* mock_conn_rewind */ + +static void +mock_conn_truncate(sdb_conn_t *conn) +{ + lseek(conn->fd, 0, SEEK_SET); + ftruncate(conn->fd, 0); +} /* mock_conn_truncate */ + +static int +mock_unixsock_listener(char *sock_path) +{ + struct sockaddr_un sa; + char *filename; + int fd, status; + + filename = tmpnam(sock_path); + fail_unless(filename != NULL, + "INTERNAL ERROR: tmpnam() = NULL; expected: a string"); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + fail_unless(fd >= 0, + "INTERNAL ERROR: socket() = %d; expected: >=0", fd); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)); + + status = bind(fd, (struct sockaddr *)&sa, sizeof(sa)); + fail_unless(status == 0, + "INTERNAL ERROR: bind() = %d; expected: 0", status); + status = listen(fd, 32); + fail_unless(status == 0, + "INTERNAL ERROR: listen() = %d; expected: 0", status); + + return fd; +} /* mock_unixsock */ + +static void * +mock_client(void *arg) +{ + char *socket_path = arg; + + struct sockaddr_un sa; + int fd, check; + + fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0); + fail_unless(fd >= 0, + "INTERNAL ERROR: socket() = %d; expected: >= 0", fd); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, socket_path, sizeof(sa.sun_path)); + + check = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); + fail_unless(check == 0, + "INTERNAL ERROR: connect() = %d; expected: 0", check); + + close(fd); + return NULL; +} /* mock_client */ + +/* + * tests + */ + +START_TEST(test_conn_accept) +{ + char socket_path[L_tmpnam]; + int fd, check; + + sdb_conn_t *conn; + + pthread_t thr; + + conn = sdb_connection_accept(-1); + fail_unless(conn == NULL, + "sdb_connection_accept(-1) = %p; expected: NULL", conn); + + memset(&socket_path, 0, sizeof(socket_path)); + fd = mock_unixsock_listener(socket_path); + check = pthread_create(&thr, /* attr = */ NULL, mock_client, socket_path); + fail_unless(check == 0, + "INTERNAL ERROR: pthread_create() = %i; expected: 0", check); + + conn = sdb_connection_accept(fd); + fail_unless(conn != NULL, + "sdb_connection_accept(%d) = %p; expected: ", fd, conn); + + unlink(socket_path); + sdb_connection_close(conn); + pthread_join(thr, NULL); +} +END_TEST + +START_TEST(test_conn_setup) +{ + sdb_conn_t *conn = mock_conn_create(); + + struct { + uint32_t code; + const char *msg; + const char *err; + } golden_data[] = { + { UINT32_MAX, NULL, NULL }, + { CONNECTION_IDLE, "fakedata", NULL }, + { CONNECTION_PING, NULL, "Authentication required" }, + { CONNECTION_STARTUP, "fakeuser", NULL }, + { CONNECTION_PING, NULL, NULL }, + { CONNECTION_IDLE, NULL, NULL }, + { CONNECTION_PING, "fakedata", NULL }, + { CONNECTION_IDLE, NULL, NULL }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + ssize_t check, expected = 0; + + mock_conn_truncate(conn); + + if (golden_data[i].code != UINT32_MAX) { + expected = 2 * sizeof(uint32_t) + + (golden_data[i].msg ? strlen(golden_data[i].msg) : 0); + + check = sdb_connection_send(conn, golden_data[i].code, + (uint32_t)(golden_data[i].msg + ? strlen(golden_data[i].msg) : 0), + golden_data[i].msg); + fail_unless(check == expected, + "sdb_connection_send(%d, %s) = %zi; expected: %zi", + golden_data[i].code, + golden_data[i].msg ? golden_data[i].msg : "", + check, expected); + } + + mock_conn_rewind(conn); + check = sdb_connection_read(conn); + fail_unless(check == expected, + "sdb_connection_read() = %zi; expected: %zi", + check, expected); + + fail_unless(sdb_strbuf_len(conn->buf) == 0, + "sdb_connection_read() left %zu bytes in the buffer; " + "expected: 0", sdb_strbuf_len(conn->buf)); + + if (golden_data[i].err) { + const char *err = sdb_strbuf_string(conn->errbuf); + fail_unless(strcmp(err, golden_data[i].err) == 0, + "sdb_connection_read(): got error '%s'; " + "expected: '%s'", err, golden_data[i].err); + } + else + fail_unless(sdb_strbuf_len(conn->errbuf) == 0, + "sdb_connection_read() left %zu bytes in the error " + "buffer; expected: 0", sdb_strbuf_len(conn->errbuf)); + } + + mock_conn_destroy(conn); +} +END_TEST + +Suite * +fe_conn_suite(void) +{ + Suite *s = suite_create("frontend::connection"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_conn_accept); + tcase_add_test(tc, test_conn_setup); + suite_add_tcase(s, tc); + + return s; +} /* fe_conn_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/frontend/parser_test.c b/t/unit/frontend/parser_test.c new file mode 100644 index 0000000..cb3a2ad --- /dev/null +++ b/t/unit/frontend/parser_test.c @@ -0,0 +1,236 @@ +/* + * SysDB - t/unit/frontend/parser_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "frontend/connection.h" +#include "frontend/parser.h" +#include "core/store-private.h" +#include "core/object.h" +#include "libsysdb_test.h" + +#include + +/* + * tests + */ + +START_TEST(test_parse) +{ + struct { + const char *query; + int len; + int expected; + sdb_conn_state_t expected_cmd; + } golden_data[] = { + /* empty commands */ + { NULL, -1, -1, 0 }, + { "", -1, 0, 0 }, + { ";", -1, 0, 0 }, + { ";;", -1, 0, 0 }, + + /* valid commands */ + { "FETCH 'host'", -1, 1, CONNECTION_FETCH }, + { "LIST", -1, 1, CONNECTION_LIST }, + { "LIST -- comment", -1, 1, CONNECTION_LIST }, + { "LIST;", -1, 1, CONNECTION_LIST }, + { "LIST; INVALID", 5, 1, CONNECTION_LIST }, + + { "LOOKUP hosts WHERE " + "host.name = 'host'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE NOT " + "host.name = 'host'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "host.name =~ 'p' AND " + "service.name =~ 'p'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE NOT " + "host.name =~ 'p' AND " + "service.name =~ 'p'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE " + "host.name =~ 'p' AND " + "service.name =~ 'p' OR " + "service.name =~ 'r'", -1, 1, CONNECTION_LOOKUP }, + { "LOOKUP hosts WHERE NOT " + "host.name =~ 'p' AND " + "service.name =~ 'p' OR " + "service.name =~ 'r'", -1, 1, CONNECTION_LOOKUP }, + + /* comments */ + { "/* some comment */", -1, 0, 0 }, + { "-- another comment", -1, 0, 0 }, + + /* syntax errors */ + { "INVALID", -1, -1, 0 }, + { "FETCH host", -1, -1, 0 }, + { "LIST; INVALID", 8, -1, 0 }, + { "/* some incomplete", -1, -1, 0 }, + + { "LOOKUP hosts", -1, -1, 0 }, + { "LOOKUP foo WHERE " + "host.name = 'host'", -1, -1, 0 }, + }; + + size_t i; + sdb_llist_t *check; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_object_t *obj; + _Bool ok; + + check = sdb_fe_parse(golden_data[i].query, golden_data[i].len); + if (golden_data[i].expected < 0) + ok = check == 0; + else + ok = sdb_llist_len(check) == (size_t)golden_data[i].expected; + + fail_unless(ok, "sdb_fe_parse(%s) = %p (len: %zu); expected: %d", + golden_data[i].query, check, sdb_llist_len(check), + golden_data[i].expected); + + if (! check) + continue; + + if ((! golden_data[i].expected_cmd) + || (golden_data[i].expected <= 0)) { + sdb_llist_destroy(check); + continue; + } + + obj = sdb_llist_get(check, 0); + fail_unless(SDB_CONN_NODE(obj)->cmd == golden_data[i].expected_cmd, + "sdb_fe_parse(%s)->cmd = %i; expected: %d", + golden_data[i].query, SDB_CONN_NODE(obj)->cmd, + golden_data[i].expected_cmd); + sdb_object_deref(obj); + sdb_llist_destroy(check); + } +} +END_TEST + +START_TEST(test_parse_matcher) +{ + struct { + const char *expr; + int len; + int expected; + } golden_data[] = { + /* empty expressions */ + { NULL, -1, -1 }, + { "", -1, -1 }, + + /* valid expressions */ + { "host.name = 'localhost'", -1, MATCHER_HOST }, + { "host.name != 'localhost'", -1, MATCHER_NOT }, + { "host.name =~ 'host'", -1, MATCHER_HOST }, + { "host.name !~ 'host'", -1, MATCHER_NOT }, + { "host.name = 'localhost' -- foo", -1, MATCHER_HOST }, + { "host.name = 'host' ", 18, MATCHER_HOST }, + /* match hosts by service */ + { "service.name = 'name'", -1, MATCHER_HOST }, + { "service.name != 'name'", -1, MATCHER_NOT }, + { "service.name =~ 'pattern'", -1, MATCHER_HOST }, + { "service.name !~ 'pattern'", -1, MATCHER_NOT }, + /* match hosts by attribute */ + { "attribute.name = 'name'", -1, MATCHER_HOST }, + { "attribute.name != 'name'", -1, MATCHER_NOT }, + { "attribute.name =~ 'pattern'", -1, MATCHER_HOST }, + { "attribute.name !~ 'pattern'", -1, MATCHER_NOT }, + /* composite expressions */ + { "host.name =~ 'pattern' AND " + "service.name =~ 'pattern'", -1, MATCHER_AND }, + { "host.name =~ 'pattern' OR " + "service.name =~ 'pattern'", -1, MATCHER_OR }, + { "NOT host.name = 'host'", -1, MATCHER_NOT }, + + /* check operator precedence */ + { "host.name = 'name' OR " + "service.name = 'name' AND " + "attribute.name = 'name' OR " + "attribute.foo = 'bar'", -1, MATCHER_OR }, + { "host.name = 'name' AND " + "service.name = 'name' AND " + "attribute.name = 'name' OR " + "attribute.foo = 'bar'", -1, MATCHER_OR }, + { "host.name = 'name' AND " + "service.name = 'name' OR " + "attribute.name = 'name' AND " + "attribute.foo = 'bar'", -1, MATCHER_OR }, + { "(host.name = 'name' OR " + "service.name = 'name') AND " + "(attribute.name = 'name' OR " + "attribute.foo = 'bar')", -1, MATCHER_AND }, + { "NOT host.name = 'name' OR " + "service.name = 'name'", -1, MATCHER_OR }, + { "NOT host.name = 'name' OR " + "NOT service.name = 'name'", -1, MATCHER_OR }, + { "NOT (host.name = 'name' OR " + "NOT service.name = 'name')", -1, MATCHER_NOT }, + + /* syntax errors */ + { "LIST", -1, -1 }, + { "foo &^ bar", -1, -1 }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_store_matcher_t *m; + m = sdb_fe_parse_matcher(golden_data[i].expr, golden_data[i].len); + + if (golden_data[i].expected < 0) { + fail_unless(m == NULL, + "sdb_fe_parse_matcher(%s) = %p; expected: NULL", + golden_data[i].expr, m); + continue; + } + + fail_unless(m != NULL, "sdb_fe_parse_matcher(%s) = NULL; " + "expected: ", golden_data[i].expr); + fail_unless(M(m)->type == golden_data[i].expected, + "sdb_fe_parse_matcher(%s) returned matcher of type %d; " + "expected: %d", golden_data[i].expr, M(m)->type, + golden_data[i].expected); + + sdb_object_deref(SDB_OBJ(m)); + } +} +END_TEST + +Suite * +fe_parser_suite(void) +{ + Suite *s = suite_create("frontend::parser"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_parse); + tcase_add_test(tc, test_parse_matcher); + suite_add_tcase(s, tc); + + return s; +} /* util_parser_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/frontend/sock_test.c b/t/unit/frontend/sock_test.c new file mode 100644 index 0000000..852a498 --- /dev/null +++ b/t/unit/frontend/sock_test.c @@ -0,0 +1,185 @@ +/* + * SysDB - t/unit/frontend/sock_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "frontend/sock.h" +#include "libsysdb_test.h" + +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +/* + * private variables + */ + +static sdb_fe_socket_t *sock; + +static void +setup(void) +{ + sock = sdb_fe_sock_create(); + fail_unless(sock != NULL, + "sdb_fe_sock_create() = NULL; expected frontend sock object"); +} /* setup */ + +static void +teardown(void) +{ + sdb_fe_sock_destroy(sock); + sock = NULL; +} /* teardown */ + +static void +sock_listen(char *tmp_file) +{ + char sock_addr[strlen("unix:") + L_tmpnam + 1]; + char *filename; + + int check; + + filename = tmpnam(tmp_file); + fail_unless(filename != NULL, + "INTERNAL ERROR: tmpnam() = NULL; expected: a string"); + + sprintf(sock_addr, "unix:%s", tmp_file); + check = sdb_fe_sock_add_listener(sock, sock_addr); + fail_unless(check == 0, + "sdb_fe_sock_add_listener(%s) = %i; expected: 0", + sock_addr, check); +} /* conn */ + +/* + * parallel testing + */ + +static void * +sock_handler(void *data) +{ + sdb_fe_loop_t *loop = data; + int check; + + check = sdb_fe_sock_listen_and_serve(sock, loop); + fail_unless(check == 0, + "sdb_fe_sock_listen_and_serve() = %i; " + "expected: 0 (after adding listener)", check); + return NULL; +} /* sock_handler */ + +/* + * tests + */ + +START_TEST(test_listen_and_serve) +{ + sdb_fe_loop_t loop = SDB_FE_LOOP_INIT; + + char tmp_file[L_tmpnam]; + int check; + + pthread_t thr; + + int sock_fd; + struct sockaddr_un sa; + + check = sdb_fe_sock_listen_and_serve(sock, &loop); + fail_unless(check < 0, + "sdb_fe_sock_listen_and_serve() = %i; " + "expected: <0 (before adding listeners)", check); + + sock_listen(tmp_file); + + loop.do_loop = 1; + check = pthread_create(&thr, /* attr = */ NULL, sock_handler, &loop); + fail_unless(check == 0, + "INTERNAL ERROR: pthread_create() = %i; expected: 0", check); + + sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); + fail_unless(sock_fd >= 0, + "INTERNAL ERROR: socket() = %d; expected: >= 0", sock_fd); + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, tmp_file, sizeof(sa.sun_path)); + + /* wait for socket to become available */ + errno = ECONNREFUSED; + while (errno == ECONNREFUSED) { + check = connect(sock_fd, (struct sockaddr *)&sa, sizeof(sa)); + if (! check) + break; + + fail_unless(errno == ECONNREFUSED, + "INTERNAL ERROR: connect() = %d [errno=%d]; expected: 0", + check, errno); + } + + close(sock_fd); + + loop.do_loop = 0; + pthread_join(thr, NULL); + + fail_unless(access(tmp_file, F_OK), + "sdb_fe_sock_listen_and_serve() did not clean up " + "socket %s", tmp_file); + + /* should do nothing and not report errors */ + check = sdb_fe_sock_listen_and_serve(sock, &loop); + fail_unless(check == 0, + "sdb_fe_sock_listen_and_serve() = %i; " + "expected: <0 (do_loop == 0)", check); + fail_unless(access(tmp_file, F_OK), + "sdb_fe_sock_listen_and_serve() recreated socket " + "(do_loop == 0)"); +} +END_TEST + +Suite * +fe_sock_suite(void) +{ + Suite *s = suite_create("frontend::sock"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, setup, teardown); + tcase_add_test(tc, test_listen_and_serve); + suite_add_tcase(s, tc); + + return s; +} /* util_unixsock_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/libsysdb_net_test.c b/t/unit/libsysdb_net_test.c new file mode 100644 index 0000000..ae213c0 --- /dev/null +++ b/t/unit/libsysdb_net_test.c @@ -0,0 +1,79 @@ +/* + * SysDB - t/unit/libsysdb_net_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * testing component involving networking operations + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "libsysdb_test.h" + +#include +#include +#include + +int +main(void) +{ + int failed = 0; + size_t i; + + suite_creator_t creators[] = { +#ifdef HAVE_FOPENCOOKIE + { util_unixsock_suite, NULL }, +#else + { NULL, "Skipping util::unixsock; missing fopencookie" }, +#endif /* HAVE_FOPENCOOKIE */ + }; + + putenv("TZ=UTC"); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(creators); ++i) { + SRunner *sr; + Suite *s; + + if (creators[i].msg) + printf("%s\n", creators[i].msg); + + if (!creators[i].creator) + continue; + + s = creators[i].creator(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + failed += srunner_ntests_failed(sr); + srunner_free(sr); + } + + return failed; +} /* main */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/libsysdb_test.c b/t/unit/libsysdb_test.c new file mode 100644 index 0000000..7d833d5 --- /dev/null +++ b/t/unit/libsysdb_test.c @@ -0,0 +1,82 @@ +/* + * SysDB - t/unit/libsysdb_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "libsysdb_test.h" + +#include +#include +#include + +int +main(void) +{ + int failed = 0; + size_t i; + + suite_creator_t creators[] = { + { core_data_suite, NULL }, + { core_object_suite, NULL }, + { core_store_suite, NULL }, + { core_store_lookup_suite, NULL }, + { core_time_suite, NULL }, + { fe_conn_suite, NULL }, + { fe_parser_suite, NULL }, + { fe_sock_suite, NULL }, + { util_channel_suite, NULL }, + { util_dbi_suite, NULL }, + { util_llist_suite, NULL }, + { util_strbuf_suite, NULL }, + }; + + putenv("TZ=UTC"); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(creators); ++i) { + SRunner *sr; + Suite *s; + + if (creators[i].msg) + printf("%s\n", creators[i].msg); + + if (!creators[i].creator) + continue; + + s = creators[i].creator(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + failed += srunner_ntests_failed(sr); + srunner_free(sr); + } + + return failed; +} /* main */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/libsysdb_test.h b/t/unit/libsysdb_test.h new file mode 100644 index 0000000..df5b904 --- /dev/null +++ b/t/unit/libsysdb_test.h @@ -0,0 +1,117 @@ +/* + * SysDB - t/unit/libsysdb_test.h + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef T_LIBSYSDB_H +#define T_LIBSYSDB_H 1 + +#include "sysdb.h" +#include "core/object.h" + +#include "libsysdb_testutils.h" + +#include +#include + +/* + * private testing helpers + */ + +/* static string object: + * Any such object may is of type sdb_object_t but may never be destroyed. */ +#define SSTRING_OBJ(name) { \ + /* type = */ { sizeof(sdb_object_t), NULL, NULL }, \ + /* ref_cnt = */ 1, /* name = */ (name) } + +/* + * test-related data-types + */ + +typedef struct { + Suite *(*creator)(void); + const char *msg; +} suite_creator_t; + +/* + * test suites + */ + +/* t/core/data_test */ +Suite * +core_data_suite(void); + +/* t/core/object_test */ +Suite * +core_object_suite(void); + +/* t/core/store_test */ +Suite * +core_store_suite(void); + +/* t/core/store_lookup_test */ +Suite * +core_store_lookup_suite(void); + +/* t/core/time_test */ +Suite * +core_time_suite(void); + +/* t/frontend/connection_test */ +Suite * +fe_conn_suite(void); + +/* t/frontend/parser_test */ +Suite * +fe_parser_suite(void); + +/* t/frontend/sock_test */ +Suite * +fe_sock_suite(void); + +/* t/utils/channel_test */ +Suite * +util_channel_suite(void); + +/* t/utils/dbi_test */ +Suite * +util_dbi_suite(void); + +/* t/utils/llist_test */ +Suite * +util_llist_suite(void); + +/* t/utils/strbuf_test */ +Suite * +util_strbuf_suite(void); + +/* t/utils/unixsock_test */ +Suite * +util_unixsock_suite(void); + +#endif /* T_LIBSYSDB_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/libsysdb_testutils.c b/t/unit/libsysdb_testutils.c new file mode 100644 index 0000000..6f6692d --- /dev/null +++ b/t/unit/libsysdb_testutils.c @@ -0,0 +1,54 @@ +/* + * SysDB - t/unit/libsysdb_testutils.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "libsysdb_testutils.h" + +#include +#include +#include + +int +sdb_regmatches(const char *regex, const char *string) +{ + regex_t reg; + int status; + + status = regcomp(®, regex, REG_EXTENDED | REG_NOSUB); + if (status) + return status; + + status = regexec(®, string, /* matches = */ 0, NULL, /* flags = */ 0); + regfree(®); + return status; +} /* sdb_regmatches */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/libsysdb_testutils.h b/t/unit/libsysdb_testutils.h new file mode 100644 index 0000000..63ef460 --- /dev/null +++ b/t/unit/libsysdb_testutils.h @@ -0,0 +1,49 @@ +/* + * SysDB - t/unit/libsysdb_testutils.h + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Utility functions for test suites. + */ + +#ifndef T_LIBSYSDB_UTILS_H +#define T_LIBSYSDB_UTILS_H 1 + +/* + * sdb_regmatches: + * Check if a regex matches a string. + * + * Returns: + * - 0 if the regex matches + * - a non-zero error value else (see regcomp(3) for details) + */ +int +sdb_regmatches(const char *regex, const char *string); + +#endif /* T_LIBSYSDB_UTILS_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/utils/channel_test.c b/t/unit/utils/channel_test.c new file mode 100644 index 0000000..0354397 --- /dev/null +++ b/t/unit/utils/channel_test.c @@ -0,0 +1,372 @@ +/* + * SysDB - t/unit/utils/channel_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/channel.h" +#include "libsysdb_test.h" + +#include +#include +#include + +#include + +static struct { + int data; + int expected_write; + int expected_read; +} golden_data_int[] = { + { 5, 0, 0 }, + { 15, 0, 0 }, + { -3, 0, 0 }, + { INT_MAX, 0, 0 }, + { 27, 0, 0 }, + { 42, 0, 0 }, + { 6, 0, 0 }, + { 2854, 0, 0 }, + { 10562, 0, 0 }, + { 0, 0, 0 }, + + /* exceeding buffer size */ + { 20, -1, -1 }, + { 42, -1, -1 }, +}; + +static struct { + char *data; + int expected_write; + int expected_read; +} golden_data_string[] = { + { "c", 0, 0 }, + { "", 0, 0 }, + { "abc", 0, 0 }, + { "foobar", 0, 0 }, + { "qux", 0, 0 }, + { "a b c", 0, 0 }, + { "123", 0, 0 }, + { "xyz", 0, 0 }, + { "b", 0, 0 }, + { "a", 0, 0 }, + + /* exceeding buffer size */ + { "err1", -1, -1 }, + { "err2", -1, -1 }, +}; + +static sdb_channel_t *chan; + +static void +setup_int(void) +{ + chan = sdb_channel_create(10, sizeof(int)); + fail_unless(chan != NULL, + "sdb_channel_create(10, sizeof(int)) = NULL; " + "expected list object"); +} /* setup_int */ + +static void +setup_string(void) +{ + chan = sdb_channel_create(10, sizeof(char *)); + fail_unless(chan != NULL, + "sdb_chan_create(10, sizeof(char *))) = NULL; " + "expected channel object"); +} /* setup_string */ + +static void +teardown(void) +{ + sdb_channel_destroy(chan); + chan = NULL; +} /* teardown */ + +START_TEST(test_create) +{ + chan = sdb_channel_create(0, 0); + fail_unless(chan == NULL, + "sdb_channel_create(0, 0) = %p; expected: NULL", chan); + + chan = sdb_channel_create(0, 1); + fail_unless(chan != NULL, + "sdb_channel_create(0, 1) = NULL; expected: channel object"); + sdb_channel_destroy(chan); + + chan = sdb_channel_create(42, 23); + fail_unless(chan != NULL, + "sdb_channel_create(32, 23) = NULL; expected: channel object"); + sdb_channel_destroy(chan); +} +END_TEST + +START_TEST(test_write_read) +{ + uint32_t data; + int check; + + chan = sdb_channel_create(0, 1); + fail_unless(chan != NULL, + "sdb_channel_create(0, 0) = NULL; expected: channel object"); + + data = 0x00ffff00; + check = sdb_channel_write(chan, &data); + fail_unless(!check, "sdb_channel_write() = %i; expected: 0", check); + check = sdb_channel_write(chan, &data); + fail_unless(check, "sdb_channel_write() = 0; expected: <0"); + + data = 0xffffffff; + check = sdb_channel_read(chan, &data); + fail_unless(check == 0, + "sdb_channel_read() = %d; expected: 0", check); + /* result depends on endianess */ + fail_unless((data == 0xffffff00) || (data == 0x00ffffff), + "sdb_channel_read() returned data %x; " + "expected: 0xffffff00 || 0x00ffffff", data); + + sdb_channel_destroy(chan); +} +END_TEST + +START_TEST(test_select) +{ + struct timespec ts = { 0, 10 }; + int check; + int data; + + chan = sdb_channel_create(0, 1); + + errno = 0; + check = sdb_channel_select(chan, &data, NULL, NULL, NULL, &ts); + fail_unless(check < ETIMEDOUT, + "sdb_channel_select() = %i; expected: <0", check); + fail_unless(errno == ETIMEDOUT, + "sdb_channel_select() set errno to %i; expected: %i (ETIMEDOUT)", + errno, ETIMEDOUT); + + check = sdb_channel_select(chan, NULL, NULL, &data, NULL, NULL); + fail_unless(! check, "sdb_channel_select() = %i; expected: 0", check); + check = sdb_channel_select(chan, NULL, NULL, &data, NULL, &ts); + fail_unless(! check, "sdb_channel_select() = %i; expected: 0", check); + + sdb_channel_destroy(chan); +} +END_TEST + +START_TEST(test_write_int) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { + int data = golden_data_int[i].data; + int expected = golden_data_int[i].expected_write; + + int check = sdb_channel_write(chan, &data); + fail_unless(check == expected, + "sdb_channel_write(chan, %i) = %i; expected: %i", + data, check, expected); + } +} +END_TEST + +START_TEST(test_read_int) +{ + size_t i; + + /* populate */ + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { + int data = golden_data_int[i].data; + int expected = golden_data_int[i].expected_write; + + int check = sdb_channel_write(chan, &data); + fail_unless(check == expected, + "sdb_channel_write(chan, %i) = %i; expected: %i", + data, check, expected); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { + int data = (int)i; + int expected = golden_data_int[i].expected_read; + + int check = sdb_channel_read(chan, &data); + fail_unless(check == expected, + "sdb_channel_read(chan, %i) = %i; expected: %i", + data, check, expected); + if (check) { + fail_unless(data == (int)i, + "sdb_channel_read() modified data to '%i'; " + "expected: no modification", data); + } + else { + fail_unless(data == golden_data_int[i].data, + "sdb_channel_read() returned data %i; expected: %i", + data, golden_data_int[i].data); + } + } +} +END_TEST + +START_TEST(test_write_read_int) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { + int data = golden_data_int[i].data; + int check = sdb_channel_write(chan, &data); + fail_unless(check == 0, + "sdb_channel_write(chan, %i) = %i; expected: 0", + data, check); + + data = (int)i; + check = sdb_channel_read(chan, &data); + fail_unless(check == 0, + "sdb_channel_read(chan, %i) = %i; expected: 0", + data, check); + if (check) { + fail_unless(data == (int)i, + "sdb_channel_read() modified data to '%i'; " + "expected: no modification", data); + } + else { + fail_unless(data == golden_data_int[i].data, + "sdb_channel_read() returned data %i; expected: %i", + data, golden_data_int[i].data); + } + } +} +END_TEST + +START_TEST(test_write_string) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { + char *data = golden_data_string[i].data; + int expected = golden_data_string[i].expected_write; + + int check = sdb_channel_write(chan, &data); + fail_unless(check == expected, + "sdb_channel_write(chan, '%s') = %i; expected: %i", + data, check, expected); + } +} +END_TEST + +START_TEST(test_read_string) +{ + size_t i; + + /* populate */ + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { + char *data = golden_data_string[i].data; + int expected = golden_data_string[i].expected_write; + + int check = sdb_channel_write(chan, &data); + fail_unless(check == expected, + "sdb_channel_write(chan, '%s') = %i; expected: %i", + data, check, expected); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { + char *data = NULL; + int expected = golden_data_string[i].expected_read; + + int check = sdb_channel_read(chan, &data); + fail_unless(check == expected, + "sdb_channel_read(chan, '') = %i; expected: %i", + check, expected); + if (check) { + fail_unless(data == NULL, + "sdb_channel_read() modified data to '%s'; " + "expected: no modification", data); + } + else { + fail_unless(data != NULL, + "sdb_channel_read() did not return any data"); + fail_unless(!strcmp(data, golden_data_string[i].data), + "sdb_channel_read() returned data '%s'; expected: '%s'", + data, golden_data_string[i].data); + } + } +} +END_TEST + +START_TEST(test_write_read_string) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { + char *data = golden_data_string[i].data; + int check = sdb_channel_write(chan, &data); + fail_unless(check == 0, + "sdb_channel_write(chan, '%s') = %i; expected: 0", + data, check); + + data = NULL; + check = sdb_channel_read(chan, &data); + fail_unless(check == 0, + "sdb_channel_read(chan, '') = %i; expected: 0", check); + if (check) { + fail_unless(data == NULL, + "sdb_channel_read() modified data to '%s'; " + "expected: no modifications", data); + } + else { + fail_unless(data != NULL, + "sdb_channel_read() did not return any data"); + fail_unless(!strcmp(data, golden_data_string[i].data), + "sdb_channel_read() returned data '%s'; expected: '%s'", + data, golden_data_string[i].data); + } + } +} +END_TEST + +Suite * +util_channel_suite(void) +{ + Suite *s = suite_create("utils::channel"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_test(tc, test_create); + tcase_add_test(tc, test_write_read); + tcase_add_test(tc, test_select); + suite_add_tcase(s, tc); + + tc = tcase_create("integer"); + tcase_add_checked_fixture(tc, setup_int, teardown); + tcase_add_test(tc, test_write_int); + tcase_add_test(tc, test_read_int); + tcase_add_test(tc, test_write_read_int); + suite_add_tcase(s, tc); + + tc = tcase_create("string"); + tcase_add_checked_fixture(tc, setup_string, teardown); + tcase_add_test(tc, test_write_string); + tcase_add_test(tc, test_read_string); + tcase_add_test(tc, test_write_read_string); + suite_add_tcase(s, tc); + + return s; +} /* util_llist_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/utils/dbi_test.c b/t/unit/utils/dbi_test.c new file mode 100644 index 0000000..b8a5ea9 --- /dev/null +++ b/t/unit/utils/dbi_test.c @@ -0,0 +1,645 @@ +/* + * SysDB - t/unit/utils/dbi_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "libsysdb_test.h" +#include "utils/dbi.h" + +#include +#include + +#define TEST_MAGIC ((void *)0x1337) + +/* + * private data-types + */ +typedef union { + long long integer; + double decimal; + const char *string; + time_t datetime; + struct { + size_t length; + const unsigned char *datum; + } binary; +} mock_data_t; + +typedef struct { + const char *name; + unsigned long long nrows; + unsigned long long current_row; + unsigned int nfields; + unsigned short *field_types; + char **field_names; +} mock_query_t; + +/* + * private variables + */ + +static sdb_dbi_client_t *client; + +/* + * mock queries + */ + +/* field definitions */ +static unsigned short field_types[] = { + DBI_TYPE_INTEGER, + DBI_TYPE_DECIMAL, + DBI_TYPE_STRING, + DBI_TYPE_DATETIME, + DBI_TYPE_BINARY, +}; +static char *field_names[] = { + "field0", + "field1", + "field2", + "field3", + "field4", +}; + +#define DATUM(p) ((const unsigned char *)(p)) +static mock_data_t golden_data[][5] = { + { + { .integer = 1234 }, + { .decimal = 1.234 }, + { .string = "abcd" }, + { .datetime = 0 }, + { .binary = { 1, DATUM("a") } }, + }, + { + { .integer = 2345 }, + { .decimal = 23.45 }, + { .string = "bcde" }, + { .datetime = 1 }, + { .binary = { 4, DATUM("bcde") } }, + }, + { + { .integer = 3456 }, + { .decimal = 345.6 }, + { .string = "cd" }, + { .datetime = 2 }, + { .binary = { 0, DATUM(NULL) } }, + }, + { + { .integer = 4567 }, + { .decimal = 4567 }, + { .string = "d" }, + { .datetime = 3 }, + { .binary = { 13, DATUM("defghijklmnop") } }, + }, + { + { .integer = 5678 }, + { .decimal = 56.78 }, + { .string = "efgh" }, + { .datetime = 4 }, + { .binary = { 5, DATUM("efghi") } }, + }, +}; + +/* query definitions */ +static mock_query_t mock_queries[] = { + { "mockquery0", 5, 1, 0, NULL, NULL }, + { "mockquery1", 0, 0, 1, field_types, field_names }, + { "mockquery2", 1, 1, 1, field_types, field_names }, + { "mockquery3", 2, 1, 1, field_types, field_names }, + { "mockquery4", 5, 1, 1, field_types, field_names }, + { "mockquery5", 5, 1, 2, field_types, field_names }, + { "mockquery6", 5, 1, 3, field_types, field_names }, + { "mockquery7", 5, 1, 4, field_types, field_names }, + { "mockquery8", 5, 1, 5, field_types, field_names }, +}; + +static mock_query_t *current_query = NULL; + +/* + * mocked functions + */ + +/* dbi_driver, dbi_conn, dbi_result are void pointers */ + +dbi_driver +dbi_driver_open(const char *name) +{ + if (strcmp(name, "mockdriver")) + return NULL; + return (dbi_driver)strdup(name); +} /* dbi_driver_open */ + +dbi_driver +dbi_driver_list(dbi_driver curr) +{ + if (!curr) + return "mockdriver"; + return NULL; +} /* dbi_driver_list */ + +const char * +dbi_driver_get_name(dbi_driver driver) +{ + return (const char *)driver; +} /* dbi_driver_get_name */ + +int +dbi_conn_set_option(dbi_conn __attribute__((unused)) conn, + const char __attribute__((unused)) *key, + const char __attribute__((unused)) *value) +{ + return 0; +} /* dbi_conn_set_option */ + +const char * +dbi_conn_get_option_list(dbi_conn __attribute__((unused)) conn, + const char __attribute__((unused)) *key) +{ + return NULL; +} /* dbi_conn_get_option_list */ + +dbi_conn +dbi_conn_open(dbi_driver driver) +{ + if (strcmp((const char *)driver, "mockdriver")) + return NULL; + return (dbi_conn)"mockconnection"; +} /* dbi_conn_open */ + +static unsigned long long dbi_conn_connect_called = 0; +int +dbi_conn_connect(dbi_conn conn) +{ + ++dbi_conn_connect_called; + if (strcmp((const char *)conn, "mockconnection")) + return DBI_ERROR_NOCONN; + return 0; +} /* dbi_conn_connect */ + +int +dbi_conn_ping(dbi_conn conn) +{ + if (strcmp((const char *)conn, "mockconnection")) + return 0; + return 1; +} /* dbi_conn_connect */ + +void +dbi_conn_close(dbi_conn __attribute__((unused)) conn) +{ + return; +} /* dbi_conn_close */ + +int +dbi_conn_error(dbi_conn conn, const char **errmsg) +{ + if ((! conn) || (strcmp((const char *)conn, "mockconnection"))) + return DBI_ERROR_BADOBJECT; + if (errmsg) + *errmsg = "mockerror"; + return DBI_ERROR_UNSUPPORTED; +} /* dbi_conn_error */ + +static unsigned long long dbi_conn_query_called = 0; +dbi_result +dbi_conn_query(dbi_conn conn, const char __attribute__((unused)) *statement) +{ + size_t i; + + ++dbi_conn_query_called; + if (strcmp((const char *)conn, "mockconnection")) + return NULL; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { + if (!strcmp(mock_queries[i].name, statement)) { + current_query = &mock_queries[i]; + return (dbi_result)current_query; + } + } + return NULL; +} /* dbi_conn_query */ + +unsigned long long +dbi_result_get_numrows(dbi_result res) +{ + mock_query_t *q = res; + if (! q) + return DBI_ROW_ERROR; + return q->nrows; +} /* dbi_result_get_numrows */ + +unsigned int +dbi_result_get_numfields(dbi_result res) +{ + mock_query_t *q = res; + if (! q) + return DBI_FIELD_ERROR; + return q->nfields; +} /* dbi_result_get_numfields */ + +unsigned short +dbi_result_get_field_type_idx(dbi_result res, unsigned int i) +{ + mock_query_t *q = res; + if ((! q) || (i > q->nfields)) + return DBI_TYPE_ERROR; + return q->field_types[i - 1]; +} /* dbi_result_get_field_type_idx */ + +const char * +dbi_result_get_field_name(dbi_result res, unsigned int i) +{ + mock_query_t *q = res; + if ((! q) || (i > q->nfields)) + return NULL; + return q->field_names[i - 1]; +} /* dbi_result_get_field_name */ + +int +dbi_result_seek_row(dbi_result res, unsigned long long n) +{ + mock_query_t *q = res; + if ((! q) || (n > q->nrows)) + return 0; + + q->current_row = n; + return 1; +} /* dbi_result_seek_row */ + +static mock_data_t +get_golden_data(dbi_result res, unsigned int i) { + mock_query_t *q = res; + fail_unless(q != NULL, "dbi_result_get_*_idx() called with " + "NULL result data; expected valid result object"); + + /* this information is managed by seek_row and, thus, + * should never be invalid */ + fail_unless(q->current_row && q->current_row <= q->nrows, + "INTERNAL ERROR: current row out of range"); + + fail_unless(i && i <= q->nfields, + "dbi_result_get_*_idx() called with index out of range; " + "got: %u; expected [1, %u]", i, q->nfields); + return golden_data[q->current_row - 1][i - 1]; +} /* get_golden_data */ + +long long +dbi_result_get_longlong_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_INTEGER, + "dbi_result_get_longlong_idx() called for non-integer " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).integer; +} /* dbi_result_get_longlong_idx */ + +double +dbi_result_get_double_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DECIMAL, + "dbi_result_get_double_idx() called for non-decimal " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).decimal; +} /* dbi_result_get_double_idx */ + +const char * +dbi_result_get_string_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING, + "dbi_result_get_string_idx() called for non-string " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).string; +} /* dbi_result_get_string_idx */ + +char * +dbi_result_get_string_copy_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING, + "dbi_result_get_string_copy_idx() called for non-string " + "column type %u", current_query->field_types[i - 1]); + if (! get_golden_data(res, i).string) + return NULL; + return strdup(get_golden_data(res, i).string); +} /* dbi_result_get_string_copy_idx */ + +time_t +dbi_result_get_datetime_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DATETIME, + "dbi_result_get_datetime_idx() called for non-datetime " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).datetime; +} /* dbi_result_get_datetime_idx */ + +size_t +dbi_result_get_field_length_idx(dbi_result res, unsigned int i) +{ + /* this will check if the parameters are valid */ + get_golden_data(res, i); + + switch (current_query->field_types[i - 1]) { + case DBI_TYPE_INTEGER: + return sizeof(long long); + break; + case DBI_TYPE_DECIMAL: + return sizeof(double); + break; + case DBI_TYPE_STRING: + return strlen(get_golden_data(res, i).string) + 1; + break; + case DBI_TYPE_DATETIME: + return sizeof(time_t); + break; + case DBI_TYPE_BINARY: + return get_golden_data(res, i).binary.length; + break; + } + + fail("INTERNAL ERROR: dbi_result_get_field_length_idx() " + "called for unexpected field type %u", + current_query->field_types[i - 1]); + return 0; +} /* dbi_result_get_field_length_idx */ + +const unsigned char * +dbi_result_get_binary_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY, + "dbi_result_get_binary_idx() called for non-binary " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).binary.datum; +} /* dbi_result_get_binary_idx */ + +unsigned char * +dbi_result_get_binary_copy_idx(dbi_result res, unsigned int i) +{ + const char *data; + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY, + "dbi_result_get_binary_copy_idx() called for non-binary " + "column type %u", current_query->field_types[i - 1]); + data = (const char *)get_golden_data(res, i).binary.datum; + if (! data) + return NULL; + return (unsigned char *)strdup(data); +} /* dbi_result_get_binary_copy_idx */ + +static unsigned long long dbi_result_free_called = 0; +int +dbi_result_free(dbi_result res) +{ + mock_query_t *q = res; + + ++dbi_result_free_called; + if (! q) + return -1; + + current_query = NULL; + return 0; +} /* dbi_result_free */ + +/* + * private helper functions + */ + +static void +setup(void) +{ + client = sdb_dbi_client_create("mockdriver", "mockdatabase"); + fail_unless(client != NULL, + "sdb_dbi_client_create() = NULL; expected client object"); + + dbi_conn_connect_called = 0; +} /* setup */ + +static void +connect(void) +{ + int check = sdb_dbi_client_connect(client); + fail_unless(check == 0, + "sdb_dbi_client_connect() = %i; expected: 0", check); +} /* connect */ + +static void +teardown(void) +{ + sdb_dbi_client_destroy(client); + client = NULL; +} /* teardown */ + +static unsigned long long query_callback_called = 0; +static int +query_callback(sdb_dbi_client_t *c, + size_t n, sdb_data_t *data, sdb_object_t *user_data) +{ + size_t i; + + ++query_callback_called; + + fail_unless(c == client, + "query callback received unexpected client = %p; " + "expected: %p", c, client); + fail_unless(n == current_query->nfields, + "query callback received n = %i; expected: %i", + n, current_query->nfields); + fail_unless(data != NULL, + "query callback received data = NULL; expected: valid data"); + fail_unless(user_data == TEST_MAGIC, + "query callback received user_data = %p; expected: %p", + user_data, TEST_MAGIC); + + for (i = 0; i < n; ++i) { + int expected_type = DBI_TYPE_TO_SC(current_query->field_types[i]); + mock_data_t expected_data; + + fail_unless((int)data[i].type == expected_type, + "query callback received unexpected type %i for " + "column %zu; expected: %i", data[i].type, i, + expected_type); + + expected_data = golden_data[current_query->current_row - 1][i]; + switch (expected_type) { + case SDB_TYPE_INTEGER: + fail_unless(data[i].data.integer == expected_data.integer, + "query callback received unexpected data %lli " + "for column %zu; expected: %lli", + data[i].data.integer, i, expected_data.integer); + break; + case SDB_TYPE_DECIMAL: + fail_unless(data[i].data.decimal == expected_data.decimal, + "query callback received unexpected data %g " + "for column %zu; expected: %g", + data[i].data.decimal, i, expected_data.decimal); + break; + case SDB_TYPE_STRING: + fail_unless(!strcmp(data[i].data.string, expected_data.string), + "query callback received unexpected data %s " + "for column %zu; expected: %s", + data[i].data.string, i, expected_data.string); + break; + case SDB_TYPE_DATETIME: + fail_unless(data[i].data.datetime + == SECS_TO_SDB_TIME(expected_data.datetime), + "query callback received unexpected data "PRIscTIME + " for column %zu; expected: "PRIscTIME, + data[i].data.integer, i, + SECS_TO_SDB_TIME(expected_data.integer)); + break; + case SDB_TYPE_BINARY: + fail_unless(data[i].data.binary.length == + expected_data.binary.length, + "query callback received unexpected " + "binary data length %zu for column %zu; " + "expected: %lli", data[i].data.binary.length, i, + expected_data.binary.length); + fail_unless(!memcmp(data[i].data.binary.datum, + expected_data.binary.datum, + expected_data.binary.length), + "query callback received unexpected binary data %p " + "for column %zu; expected: %p", + data[i].data.binary.datum, i, + expected_data.binary.datum); + break; + default: + fail("INTERNAL ERROR: query callback received " + "unknown type %i for column %zu", + expected_type, i); + } + } + return 0; +} /* query_callback */ + +/* + * tests + */ + +START_TEST(test_sdb_dbi_client_connect) +{ + int check = sdb_dbi_client_connect(client); + fail_unless(check == 0, + "sdb_dbi_client_connect() = %i; expected: 0", check); + + fail_unless(dbi_conn_connect_called == 1, + "sdb_dbi_client_create() called dbi_conn_connect %i times; " + "expected: 1", dbi_conn_connect_called); +} +END_TEST + +START_TEST(test_sdb_dbi_client_check_conn) +{ + int check = sdb_dbi_client_check_conn(client); + fail_unless(check == 0, + "sdb_dbi_client_check_conn() = %i; expected: 0", check); + + /* the first call will actually connect to the database */ + fail_unless(dbi_conn_connect_called == 1, + "sdb_dbi_client_check_conn() called dbi_conn_connect %i times; " + "expected: 1", dbi_conn_connect_called); + + dbi_conn_connect_called = 0; + check = sdb_dbi_client_check_conn(client); + fail_unless(check == 0, + "sdb_dbi_client_check_conn() = %i; expected: 0", check); + + /* should not reconnect */ + fail_unless(dbi_conn_connect_called == 0, + "sdb_dbi_client_check_conn() called dbi_conn_connect %i time(s); " + "expected: 0", dbi_conn_connect_called); +} +END_TEST + +START_TEST(test_sdb_dbi_exec_query) +{ + size_t i; + + int check = sdb_dbi_exec_query(client, "mockquery0", query_callback, + /* user_data = */ TEST_MAGIC, /* n = */ 0); + /* not connected yet */ + fail_unless(check < 0, + "sdb_dbi_exec_query() = %i; expected: < 0", check); + + connect(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { + mock_query_t *q = &mock_queries[i]; + + unsigned long long expected_callback_calls = 0; + + dbi_conn_query_called = 0; + query_callback_called = 0; + dbi_result_free_called = 0; + + /* sdb_dbi_exec_query will only use as many type arguments are needed, + * so we can safely pass in the maximum number of arguments required + * on each call */ + check = sdb_dbi_exec_query(client, q->name, query_callback, + /* user_data = */ TEST_MAGIC, /* n = */ (int)q->nfields, + SDB_TYPE_INTEGER, SDB_TYPE_DECIMAL, SDB_TYPE_STRING, + SDB_TYPE_DATETIME, SDB_TYPE_BINARY); + fail_unless(check == 0, + "sdb_dbi_exec_query() = %i; expected: 0", check); + + fail_unless(dbi_conn_query_called == 1, + "sdb_dbi_exec_query() called dbi_conn_query %i times; " + "expected: 1", dbi_conn_query_called); + + if (q->nfields) + expected_callback_calls = q->nrows; + + fail_unless(query_callback_called == expected_callback_calls, + "sdb_dbi_exec_query() did not call the registered callback " + "for each result row; got %i call%s; expected: 0", + query_callback_called, + (query_callback_called == 1) ? "" : "s"); + + fail_unless(dbi_result_free_called == 1, + "sdb_dbi_exec_query() did not free the query result object"); + } +} +END_TEST + +/* + * test API + */ + +Suite * +util_dbi_suite(void) +{ + Suite *s = suite_create("utils::dbi"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, setup, teardown); + tcase_add_test(tc, test_sdb_dbi_client_connect); + tcase_add_test(tc, test_sdb_dbi_client_check_conn); + tcase_add_test(tc, test_sdb_dbi_exec_query); + suite_add_tcase(s, tc); + + return s; +} /* util_llist_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/utils/llist_test.c b/t/unit/utils/llist_test.c new file mode 100644 index 0000000..5ae771f --- /dev/null +++ b/t/unit/utils/llist_test.c @@ -0,0 +1,399 @@ +/* + * SysDB - t/unit/utils/llist_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/llist.h" +#include "libsysdb_test.h" + +#include + +/* + * private data types + */ + +static sdb_object_t golden_data[] = { + SSTRING_OBJ("abc"), + SSTRING_OBJ("bcd"), + SSTRING_OBJ("cde"), + SSTRING_OBJ("def"), + SSTRING_OBJ("efg"), + SSTRING_OBJ("fgh"), + SSTRING_OBJ("ghi") +}; + +static char *unused_names[] = { + "xyz", + "yza", + "zab" +}; + +static sdb_llist_t *list; + +static void +setup(void) +{ + list = sdb_llist_create(); + fail_unless(list != NULL, + "sdb_llist_create() = NULL; expected list object"); +} /* setup */ + +static void +teardown(void) +{ + sdb_llist_destroy(list); + list = NULL; +} /* teardown */ + +/* populate the list with the golden data in the specified order */ +static void +populate(void) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int check = sdb_llist_append(list, &golden_data[i]); + fail_unless(check == 0, + "sdb_llist_append(%s) = %i; expected: 0", + golden_data[i].name, check); + } +} /* populate */ + +START_TEST(test_clone) +{ + sdb_llist_t *clone; + size_t i; + + populate(); + + clone = sdb_llist_clone(list); + fail_unless(clone != NULL, + "sdb_llist_clone() = NULL; expected: cloned list object"); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + fail_unless(golden_data[i].ref_cnt == 3, + "sdb_llist_clone() did not take ownership"); + } + + sdb_llist_destroy(clone); +} +END_TEST + +START_TEST(test_destroy) +{ + size_t i; + populate(); + sdb_llist_destroy(list); + list = NULL; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + fail_unless(golden_data[i].ref_cnt == 1, + "sdb_llist_destroy() did not deref element %s", + golden_data[i].name); + } +} +END_TEST + +START_TEST(test_clear) +{ + size_t i; + populate(); + sdb_llist_clear(list); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + fail_unless(golden_data[i].ref_cnt == 1, + "sdb_llist_clear() did not deref element %s", + golden_data[i].name); + } + + i = sdb_llist_len(list); + fail_unless(i == 0, + "sdb_llist_clear() left %zu elements in the list; " + "expected: 0", i); +} +END_TEST + +START_TEST(test_append) +{ + size_t i; + + fail_unless(sdb_llist_len(list) == 0, + "sdb_llist_len() = %zu; expected: 0", + sdb_llist_len(list)); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int check = sdb_llist_append(list, &golden_data[i]); + fail_unless(check == 0, + "sdb_llist_append(%s) = %i; expected: 0", + golden_data[i].name, check); + fail_unless(golden_data[i].ref_cnt == 2, + "sdb_llist_append(%s) did not take ownership", + golden_data[i].name); + fail_unless(sdb_llist_len(list) == i + 1, + "sdb_llist_len() = %zu; expected: zu", + sdb_llist_len(list), i + 1); + } +} +END_TEST + +START_TEST(test_insert) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int check = sdb_llist_insert(list, &golden_data[i], 0); + fail_unless(check == 0, + "sdb_llist_insert(%s, 0) = %i; expected: 0", + golden_data[i].name, check); + fail_unless(golden_data[i].ref_cnt == 2, + "sdb_llist_insert(%s, 0) did not take ownership", + golden_data[i].name); + } +} +END_TEST + +START_TEST(test_validate_insert) +{ + size_t i; + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + /* none of these operations will succeed + * => 1 is invalid for each case */ + int check = sdb_llist_insert(list, &golden_data[i], 1); + fail_unless(check == -1, + "sdb_llist_insert(%s, 1) = %i; expected: -1", + golden_data[i].name, check); + fail_unless(golden_data[i].ref_cnt == 1, + "sdb_llist_insert(%s, 1) took ownership", + golden_data[i].name); + } +} +END_TEST + +START_TEST(test_get) +{ + size_t i; + populate(); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_object_t *check = sdb_llist_get(list, i); + fail_unless(check == &golden_data[i], + "sdb_llist_get() = %p; expected: %p", + check, &golden_data[i]); + fail_unless(check->ref_cnt == 3, + "sdb_llist_get() didn't increment reference count; got: %i; " + "expected: 3", check->ref_cnt); + sdb_object_deref(check); + } +} +END_TEST + +START_TEST(test_remove_by_name) +{ + /* "random" indexes */ + int indexes[] = { 4, 5, 3, 6, 2, 0, 1 }; + size_t i; + + populate(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(indexes); ++i) { + sdb_object_t *check; + + fail_unless((size_t)indexes[i] < SDB_STATIC_ARRAY_LEN(golden_data), + "INTERNAL ERROR: invalid index %i", indexes[i]); + + check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name); + fail_unless(check == &golden_data[indexes[i]], + "sdb_llist_remove_by_name() = %p; expected: %p", + check, &golden_data[indexes[i]]); + fail_unless(check->ref_cnt == 2, + "sdb_llist_remove_by_name() returned unexpected reference " + "count; got: %i; expected: 2", check->ref_cnt); + + check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name); + fail_unless(check == NULL, + "sdb_llist_remove_by_name() did not remove the element"); + } +} +END_TEST + +static int +dummy_lookup(const sdb_object_t __attribute__((unused)) *obj, + const void __attribute__((unused)) *user_data) +{ + return 0; +} /* dummy_lookup */ + +START_TEST(test_search) +{ + size_t i; + populate(); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_object_t *check = sdb_llist_search_by_name(list, + golden_data[i].name); + fail_unless(check == &golden_data[i], + "sdb_llist_search_by_name(%s) = NULL; expected: %p", + golden_data[i].name, &golden_data[i]); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(unused_names); ++i) { + sdb_object_t *check = sdb_llist_search_by_name(list, + unused_names[i]); + fail_unless(check == NULL, + "sdb_llist_search_by_name(%s) = %p; expected: NULL", + unused_names[i], check); + } + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + /* dummy_lookup always return 0, thus, this will always return the + * first element */ + sdb_object_t *check = sdb_llist_search(list, dummy_lookup, NULL); + fail_unless(check == &golden_data[i], + "sdb_llist_search() = %p (%s); expected: %p (%s)", + check, check->name, &golden_data[i], golden_data[i].name); + + /* => remove the first element */ + check = sdb_llist_remove(list, dummy_lookup, NULL); + fail_unless(check == &golden_data[i], + "sdb_llist_remove() = %p (%s); expected: %p (%s)", + check, check->name, &golden_data[i], golden_data[i].name); + fail_unless(check->ref_cnt == 2, + "sdb_llist_remove() changed reference count; got: %i; " + "expected: 2", check->ref_cnt); + } + /* should now be empty */ + fail_unless(sdb_llist_len(list) == 0, + "Still have %i elements in the list; expected: 0", + sdb_llist_len(list)); +} +END_TEST + +START_TEST(test_shift) +{ + size_t i; + populate(); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_object_t *check = sdb_llist_shift(list); + fail_unless(check == &golden_data[i], + "sdb_llist_shift() = NULL; expected: %p", + &golden_data[i]); + fail_unless(check->ref_cnt == 2, + "sdb_llist_shift() changed reference count; got: %i; " + "expected: 2", check->ref_cnt); + } + + /* must be empty now */ + fail_unless(sdb_llist_shift(list) == NULL, + "sdb_llist_shift() returned value; expected: NULL"); +} +END_TEST + +START_TEST(test_iter) +{ + sdb_llist_iter_t *iter; + size_t i; + + populate(); + + iter = sdb_llist_get_iter(list); + fail_unless(iter != NULL, + "sdb_llist_get_iter() did not return an iterator"); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_object_t *check; + fail_unless(sdb_llist_iter_has_next(iter), + "sdb_llist_iter_has_next() = FALSE; expected: TRUE"); + check = sdb_llist_iter_get_next(iter); + fail_unless(check == &golden_data[i], + "sdb_llist_iter_get_next() = %p; expected: %p", + check, &golden_data[i]); + } + + fail_unless(!sdb_llist_iter_has_next(iter), + "sdb_llist_iter_has_next() = TRUE; expected: FALSE"); + fail_unless(sdb_llist_iter_get_next(iter) == NULL, + "sdb_llist_iter_get_next() returned value; expected: NULL"); + sdb_llist_iter_destroy(iter); +} +END_TEST + +START_TEST(test_iter_remove) +{ + sdb_llist_iter_t *iter; + sdb_object_t *check; + size_t i; + + populate(); + + iter = sdb_llist_get_iter(list); + fail_unless(iter != NULL, + "sdb_llist_get_iter() did not return an iterator"); + + i = 0; + while (sdb_llist_iter_has_next(iter)) { + check = sdb_llist_iter_get_next(iter); + fail_unless(check == &golden_data[i], + "sdb_llist_iter_get_next() = %p; expected: %p", + check, &golden_data[i]); + + sdb_llist_iter_remove_current(iter); + ++i; + } + sdb_llist_iter_destroy(iter); + + fail_unless(i == (size_t)SDB_STATIC_ARRAY_LEN(golden_data), + "iterated for %zu steps; expected: %i", + i, SDB_STATIC_ARRAY_LEN(golden_data)); + + /* all elements should be removed */ + check = sdb_llist_shift(list); + fail_unless(check == NULL, + "sdb_llist_shift() = %p; expected: NULL", check); +} +END_TEST + +Suite * +util_llist_suite(void) +{ + Suite *s = suite_create("utils::llist"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, setup, teardown); + tcase_add_test(tc, test_clone); + tcase_add_test(tc, test_destroy); + tcase_add_test(tc, test_clear); + tcase_add_test(tc, test_append); + tcase_add_test(tc, test_insert); + tcase_add_test(tc, test_validate_insert); + tcase_add_test(tc, test_get); + tcase_add_test(tc, test_remove_by_name); + tcase_add_test(tc, test_search); + tcase_add_test(tc, test_shift); + tcase_add_test(tc, test_iter); + tcase_add_test(tc, test_iter_remove); + suite_add_tcase(s, tc); + + return s; +} /* util_llist_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/utils/strbuf_test.c b/t/unit/utils/strbuf_test.c new file mode 100644 index 0000000..f9c3e93 --- /dev/null +++ b/t/unit/utils/strbuf_test.c @@ -0,0 +1,564 @@ +/* + * SysDB - t/unit/utils/strbuf_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/strbuf.h" +#include "libsysdb_test.h" + +#include + +/* + * private data types + */ + +static sdb_strbuf_t *buf; + +static void +setup(void) +{ + buf = sdb_strbuf_create(0); + fail_unless(buf != NULL, + "sdb_strbuf_create() = NULL; expected strbuf object"); +} /* setup */ + +static void +teardown(void) +{ + sdb_strbuf_destroy(buf); + buf = NULL; +} /* teardown */ + +/* + * tests + */ + +START_TEST(test_null) +{ + sdb_strbuf_t *b = NULL; + va_list ap; + + /* check that methods don't crash */ + sdb_strbuf_destroy(b); + sdb_strbuf_skip(b, 0, 0); + sdb_strbuf_skip(b, 0, 10); + sdb_strbuf_skip(b, 10, 10); + sdb_strbuf_clear(b); + + /* check that methods return an error */ + fail_unless(sdb_strbuf_vappend(b, "test", ap) < 0, + "sdb_strbuf_vappend(NULL) didn't report failure"); + fail_unless(sdb_strbuf_append(b, "test") < 0, + "sdb_strbuf_append(NULL) didn't report failure"); + fail_unless(sdb_strbuf_vsprintf(b, "test", ap) < 0, + "sdb_strbuf_vsprintf(NULL) didn't report failure"); + fail_unless(sdb_strbuf_sprintf(b, "test") < 0, + "sdb_strbuf_sprintf(NULL) didn't report failure"); + fail_unless(sdb_strbuf_memcpy(b, "test", 4) < 0, + "sdb_strbuf_memcpy(NULL) didn't report failure"); + fail_unless(sdb_strbuf_memappend(b, "test", 4) < 0, + "sdb_strbuf_memappend(NULL) didn't report failure"); + fail_unless(sdb_strbuf_read(b, 0, 32) < 0, + "sdb_strbuf_read(NULL) didn't report failure"); + fail_unless(sdb_strbuf_chomp(b) < 0, + "sdb_strbuf_chomp(NULL) didn't report failure"); +} +END_TEST + +START_TEST(test_empty) +{ + sdb_strbuf_t *b = sdb_strbuf_create(0); + const char *data; + size_t len; + + /* check that methods don't crash */ + sdb_strbuf_skip(b, 1, 1); + sdb_strbuf_clear(b); + sdb_strbuf_chomp(b); + + data = sdb_strbuf_string(b); + fail_unless(data && (*data == '\0'), + "sdb_strbuf_string() = '%s'; expected: ''", data); + len = sdb_strbuf_len(b); + fail_unless(len == 0, + "sdb_strbuf_len() = %zu; expected: 0", len); + + sdb_strbuf_destroy(b); +} +END_TEST + +START_TEST(test_sdb_strbuf_create) +{ + sdb_strbuf_t *s; + size_t len; + + s = sdb_strbuf_create(0); + fail_unless(s != NULL, + "sdb_strbuf_create() = NULL; expected strbuf object"); + len = sdb_strbuf_len(s); + fail_unless(len == 0, + "sdb_strbuf_create() created buffer with len = %zu; " + "expected: 0", len); + sdb_strbuf_destroy(s); + + s = sdb_strbuf_create(128); + fail_unless(s != NULL, + "sdb_strbuf_create() = NULL; expected strbuf object"); + len = sdb_strbuf_len(s); + /* len still has to be 0 -- there's no content */ + fail_unless(len == 0, + "sdb_strbuf_create() created buffer with len = %zu; " + "expected: 0", len); + sdb_strbuf_destroy(s); +} +END_TEST + +START_TEST(test_sdb_strbuf_append) +{ + ssize_t n, expected; + size_t len; + const char *test; + + n = sdb_strbuf_append(buf, "1234567890"); + fail_unless(n == 10, + "sdb_strbuf_append() appended %zi bytes; expected: 10", n); + len = sdb_strbuf_len(buf); + fail_unless(len == 10, + "sdb_strbuf_append() left behind buffer with len = %zu; " + "expected: 10", len); + + n = sdb_strbuf_append(buf, "ABCDE"); + fail_unless(n == 5, + "sdb_strbuf_append() appended %zi bytes; expected: 5", n); + len = sdb_strbuf_len(buf); + fail_unless(len == 15, + "sdb_strbuf_append() left behind buffer with len = %zu; " + "expected: 15", len); + + test = sdb_strbuf_string(buf); + fail_unless(test[len] == '\0', + "sdb_strbuf_append() did not nil-terminate the string"); + fail_unless(!strcmp(test, "1234567890ABCDE"), + "sdb_strbuf_append() did not correctly concatenate two string; " + "got: %s; expected: 1234567890ABCDE", test); + + n = sdb_strbuf_append(buf, "%zu; %5.4f", len, (double)len / 10.0); + expected = /* len */ 2 + /* "; " */ 2 + /* decimal len/10 */ 6; + fail_unless(n == expected, + "sdb_strbuf_append() appended %zi bytes; expected: %zi", + n, expected); + len = sdb_strbuf_len(buf); + fail_unless(len == 15 + (size_t)expected, + "sdb_strbuf_append() left behind buffer with len = %zu; " + "expected: %zu", len, 15 + (size_t)expected); + + test = sdb_strbuf_string(buf); + fail_unless(test[len] == '\0', + "sdb_strbuf_append() did not nil-terminate the string"); + fail_unless(!strcmp(test, "1234567890ABCDE15; 1.5000"), + "sdb_strbuf_append() did not correctly concatenate two string; " + "got: %s; expected: 1234567890ABCDE15; 1.5000", test); +} +END_TEST + +START_TEST(test_sdb_strbuf_sprintf) +{ + ssize_t n, expected; + size_t len; + const char *test; + + n = sdb_strbuf_sprintf(buf, "1234567890"); + fail_unless(n == 10, + "sdb_strbuf_sprintf() wrote %zi bytes; expected: 10", n); + len = sdb_strbuf_len(buf); + fail_unless(len == 10, + "sdb_strbuf_sprintf() left behind buffer with len = %zu; " + "expected: 10", len); + + n = sdb_strbuf_sprintf(buf, "ABCDE"); + fail_unless(n == 5, + "sdb_strbuf_sprintf() wrote %zi bytes; expected: 5", n); + len = sdb_strbuf_len(buf); + fail_unless(len == 5, + "sdb_strbuf_sprintf() left behind buffer with len = %zu; " + "expected: 5", len); + + test = sdb_strbuf_string(buf); + fail_unless(test[len] == '\0', + "sdb_strbuf_sprintf() did not nil-terminate the string"); + fail_unless(!strcmp(test, "ABCDE"), + "sdb_strbuf_sprintf() did not format string correctly; " + "got: %s; expected: ABCDE", test); + + n = sdb_strbuf_sprintf(buf, "%zu; %5.4f", len, (double)len / 10.0); + expected = /* len */ 1 + /* "; " */ 2 + /* decimal len/10 */ 6; + fail_unless(n == expected, + "sdb_strbuf_sprintf() wrote %zi bytes; expected: %zi", + n, expected); + len = sdb_strbuf_len(buf); + fail_unless(len == (size_t)expected, + "sdb_strbuf_sprintf() left behind buffer with len = %zu; " + "expected: %zu", len, (size_t)expected); + + test = sdb_strbuf_string(buf); + fail_unless(test[len] == '\0', + "sdb_strbuf_sprintf() did not nil-terminate the string"); + fail_unless(!strcmp(test, "5; 0.5000"), + "sdb_strbuf_sprintf() did not format string correctly; " + "got: %s; expected: 5; 0.5000", test); +} +END_TEST + +START_TEST(test_incremental) +{ + ssize_t n; + size_t i; + + sdb_strbuf_destroy(buf); + buf = sdb_strbuf_create(1024); + + /* fill buffer one by one; leave room for nul-byte */ + for (i = 0; i < 1023; ++i) { + n = sdb_strbuf_append(buf, "."); + fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); + } + + /* write another byte; this has to trigger a resize */ + n = sdb_strbuf_append(buf, "."); + fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); + + /* write more bytes; this should trigger at least one more resize but + * that's an implementation detail */ + for (i = 0; i < 1024; ++i) { + n = sdb_strbuf_append(buf, "."); + fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); + } + + n = (ssize_t)sdb_strbuf_len(buf); + fail_unless(n == 2048, "sdb_strbuf_len() = %zi; expectd: 2048", n); +} +END_TEST + +static struct { + const char *input; + size_t size; +} mem_golden_data[] = { + { "abc\0\x10\x42", 6 }, + { "\0\1\2\3\4", 5 }, + { "\n\n\0\n\n", 5 }, + { "", 0 }, +}; + +START_TEST(test_sdb_strbuf_memcpy) +{ + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) { + ssize_t n; + const char *check; + + n = sdb_strbuf_memcpy(buf, mem_golden_data[i].input, + mem_golden_data[i].size); + fail_unless(n >= 0, + "sdb_strbuf_memcpy() = %zi; expected: >=0", n); + fail_unless((size_t)n == mem_golden_data[i].size, + "sdb_strbuf_memcpy() = %zi; expected: %zu", + n, mem_golden_data[i].size); + + n = (ssize_t)sdb_strbuf_len(buf); + fail_unless((size_t)n == mem_golden_data[i].size, + "sdb_strbuf_len() = %zu (after memcpy); expected: %zu", + n, mem_golden_data[i].size); + + check = sdb_strbuf_string(buf); + fail_unless(check != NULL, + "sdb_strbuf_string() = NULL (after memcpy); expected: data"); + fail_unless(check[mem_golden_data[i].size] == '\0', + "sdb_strbuf_memcpy() did not nil-terminate the data"); + fail_unless(!memcmp(check, mem_golden_data[i].input, + mem_golden_data[i].size), + "sdb_strbuf_memcpy() did not set the buffer correctly"); + } +} +END_TEST + +START_TEST(test_sdb_strbuf_memappend) +{ + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) { + ssize_t n; + const char *check; + + size_t total, j; + + n = sdb_strbuf_memappend(buf, mem_golden_data[i].input, + mem_golden_data[i].size); + fail_unless(n >= 0, + "sdb_strbuf_memappend() = %zi; expected: >=0", n); + fail_unless((size_t)n == mem_golden_data[i].size, + "sdb_strbuf_memappend() = %zi; expected: %zu", + n, mem_golden_data[i].size); + + check = sdb_strbuf_string(buf); + fail_unless(check != NULL, + "sdb_strbuf_string() = NULL (after memappend); " + "expected: data"); + + n = (ssize_t)sdb_strbuf_len(buf); + total = 0; + for (j = 0; j <= i; ++j) { + fail_unless(total + mem_golden_data[j].size <= (size_t)n, + "sdb_strbuf_len() = %zu (after memappend); " + "expected: >=%zu", n, total + mem_golden_data[j].size); + + fail_unless(!memcmp(check + total, mem_golden_data[j].input, + mem_golden_data[j].size), + "sdb_strbuf_memappend() did not " + "set the buffer correctly"); + total += mem_golden_data[j].size; + } + fail_unless((size_t)n == total, + "sdb_strbuf_len() = %zu (after memappend); expected: %zu", + n, total); + + fail_unless(check[total] == '\0', + "sdb_strbuf_memappend() did not nil-terminate the data"); + } +} +END_TEST + +static struct { + const char *input; + ssize_t expected; + const char *expected_string; +} chomp_golden_data[] = { + { NULL, 0, "" }, + { "\n", 1, "" }, + { "\n\n", 2, "" }, + { "12345\n\n\n", 3, "12345" }, + { "abcd", 0, "abcd" }, +}; + +START_TEST(test_sdb_strbuf_chomp) +{ + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(chomp_golden_data); ++i) { + ssize_t n; + const char *check; + + if (chomp_golden_data[i].input) + sdb_strbuf_sprintf(buf, chomp_golden_data[i].input); + + /* empty buffer */ + n = sdb_strbuf_chomp(buf); + fail_unless(n == chomp_golden_data[i].expected, + "sdb_strbuf_chomp() = %zi; expected: %zi", n, + chomp_golden_data[i].expected); + + check = sdb_strbuf_string(buf); + fail_unless(!strcmp(check, chomp_golden_data[i].expected_string), + "sdb_strbuf_chomp() did not correctly remove newlines; " + "got string '%s'; expected: '%s'", check, + chomp_golden_data[i].expected_string); + } +} +END_TEST + +/* input is "1234567890" */ +static struct { + size_t offset; + size_t n; + const char *expected; + size_t expected_len; +} skip_golden_data[] = { + { 0, 0, "1234567890", 10 }, + { 0, 1, "234567890", 9 }, + { 0, 2, "34567890", 8 }, + { 0, 9, "0", 1 }, + { 0, 10, "", 0 }, + { 0, 11, "", 0 }, + { 0, 100, "", 0 }, + { 1, 0, "1234567890", 10 }, + { 1, 1, "134567890", 9 }, + { 1, 2, "14567890", 8 }, + { 2, 0, "1234567890", 10 }, + { 2, 1, "124567890", 9 }, + { 2, 2, "12567890", 8 }, + { 2, 3, "1267890", 7 }, + { 2, 4, "127890", 6 }, + { 2, 5, "12890", 5 }, + { 2, 6, "1290", 4 }, + { 2, 7, "120", 3 }, + { 2, 8, "12", 2 }, + { 2, 9, "12", 2 }, + { 2, 10, "12", 2 }, + { 8, 1, "123456780", 9 }, + { 8, 2, "12345678", 8 }, + { 8, 3, "12345678", 8 }, + { 9, 1, "123456789", 9 }, + { 9, 2, "123456789", 9 }, + { 10, 1, "1234567890", 10 }, + { 10, 2, "1234567890", 10 }, +}; + +START_TEST(test_sdb_strbuf_skip) +{ + const char *input = "1234567890"; + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(skip_golden_data); ++i) { + const char *check; + size_t n; + + sdb_strbuf_sprintf(buf, input); + sdb_strbuf_skip(buf, skip_golden_data[i].offset, + skip_golden_data[i].n); + + n = sdb_strbuf_len(buf); + fail_unless(n == skip_golden_data[i].expected_len, + "sdb_strbuf_len() = %zu (after skip); expected: %zu", + n, skip_golden_data[i].expected_len); + + check = sdb_strbuf_string(buf); + fail_unless(!!check, + "sdb_strbuf_string() = NULL (after skip); expected: string"); + + fail_unless(check[n] == '\0', + "sdb_strbuf_skip() did not nil-terminate the string"); + + fail_unless(! strcmp(skip_golden_data[i].expected, check), + "sdb_strbuf_skip('%s', %zu) did not skip correctly; " + "got string '%s'; expected: '%s'", input, + skip_golden_data[i].n, check, skip_golden_data[i].expected); + } +} +END_TEST + +START_TEST(test_sdb_strbuf_clear) +{ + const char *data; + size_t len; + + sdb_strbuf_append(buf, "abc"); + len = sdb_strbuf_len(buf); + fail_unless(len != 0, + "sdb_strbuf_len() = %zu; expected: != 0", len); + + sdb_strbuf_clear(buf); + len = sdb_strbuf_len(buf); + fail_unless(len == 0, + "sdb_strbuf_len() = %zu (after clear); expected: 0", len); + + data = sdb_strbuf_string(buf); + fail_unless(*data == '\0', + "sdb_strbuf_string() = '%s' (after clear); expected: ''", data); +} +END_TEST + +static struct { + const char *input; + const char *expected; +} string_golden_data[] = { + { NULL, "" }, + { "a", "a" }, + { "abcdef", "abcdef" }, +}; + +START_TEST(test_sdb_strbuf_string) +{ + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(string_golden_data); ++i) { + const char *check; + + if (string_golden_data[i].input) + sdb_strbuf_sprintf(buf, string_golden_data[i].input); + check = sdb_strbuf_string(buf); + fail_unless(!strcmp(check, string_golden_data[i].expected), + "sdb_strbuf_string() = '%s'; expected: '%s'", + check, string_golden_data[i].expected); + } +} +END_TEST + +static struct { + const char *input; + size_t expected; +} len_golden_data[] = { + { NULL, 0 }, + { "a", 1 }, + { "12345", 5 }, +}; + +START_TEST(test_sdb_strbuf_len) +{ + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(len_golden_data); ++i) { + size_t check; + + if (len_golden_data[i].input) + sdb_strbuf_sprintf(buf, len_golden_data[i].input); + check = sdb_strbuf_len(buf); + fail_unless(check == len_golden_data[i].expected, + "sdb_strbuf_len() = %zu; expected: %zu", + check, len_golden_data[i].expected); + } +} +END_TEST + +Suite * +util_strbuf_suite(void) +{ + Suite *s = suite_create("utils::strbuf"); + TCase *tc; + + tc = tcase_create("empty"); + tcase_add_test(tc, test_null); + tcase_add_test(tc, test_empty); + suite_add_tcase(s, tc); + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, setup, teardown); + tcase_add_test(tc, test_sdb_strbuf_create); + tcase_add_test(tc, test_sdb_strbuf_append); + tcase_add_test(tc, test_sdb_strbuf_sprintf); + tcase_add_test(tc, test_incremental); + tcase_add_test(tc, test_sdb_strbuf_memcpy); + tcase_add_test(tc, test_sdb_strbuf_memappend); + tcase_add_test(tc, test_sdb_strbuf_chomp); + tcase_add_test(tc, test_sdb_strbuf_skip); + tcase_add_test(tc, test_sdb_strbuf_clear); + tcase_add_test(tc, test_sdb_strbuf_string); + tcase_add_test(tc, test_sdb_strbuf_len); + suite_add_tcase(s, tc); + + return s; +} /* util_strbuf_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/unit/utils/unixsock_test.c b/t/unit/utils/unixsock_test.c new file mode 100644 index 0000000..c28781e --- /dev/null +++ b/t/unit/utils/unixsock_test.c @@ -0,0 +1,381 @@ +/* + * SysDB - t/unit/utils/unixsock_test.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +/* required for fopencookie support */ +#define _GNU_SOURCE + +#include "utils/unixsock.h" +#include "libsysdb_test.h" + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +/* + * I/O "hook" functions + */ + +typedef struct { + int fd; + size_t pos; +} io_cookie_t; + +static struct { + const char *data; + size_t len; +} golden_data[] = { + { "a", 1 }, + { "abc", 3 }, + { "12345", 5 }, + { "", 0 }, +}; + +static char *last_write = NULL; + +static unsigned long long mock_read_called = 0; +static ssize_t +mock_read(void *cookie, char *buf, size_t size) +{ + io_cookie_t *c = cookie; + ssize_t ret; + + ++mock_read_called; + + if (c->pos >= SDB_STATIC_ARRAY_LEN(golden_data)) + return 0; + + ret = snprintf(buf, size, "%s\n", golden_data[c->pos].data); + ++c->pos; + return ret; +} /* mock_read */ + +static unsigned long long mock_write_called = 0; +static ssize_t +mock_write(void *cookie, const char *buf, size_t size) +{ + io_cookie_t *c = cookie; + + ++mock_write_called; + + if (c->pos >= SDB_STATIC_ARRAY_LEN(golden_data)) + return 0; + + if (last_write) + free(last_write); + last_write = strdup(buf); + ++c->pos; + return (ssize_t)size; +} /* mock_write */ + +/* unsupported: int seek(void *cookie, off64_t *offset, int whence) */ + +static int +mock_close(void *cookie) +{ + io_cookie_t *c = cookie; + + if (! c) + return EBADF; + + close(c->fd); + free(c); + return 0; +} /* mock_close */ + +static cookie_io_functions_t mock_io = { + /* read = */ mock_read, + /* write = */ mock_write, + /* seek = */ NULL, + /* close = */ mock_close, +}; + +/* + * mocked functions + */ + +static int myfd = -1; + +static void * +dlopen_libc(void) +{ + static void *libc = NULL; + + if (libc) + return libc; + + libc = dlopen("libc.so.6", RTLD_LAZY); + if (! libc) + fail("INTERNAL ERROR: failed to load libc"); + return libc; +} /* dlopen_libc */ + +int +socket(int domain, int __attribute__((unused)) type, + int __attribute__((unused)) protocol) +{ + char tmp_file[] = "unixsock_test_socket.XXXXXX"; + int tmp_fd; + + /* we only want to mock UNIX sockets; return an error else */ + if (domain != AF_UNIX) { + errno = EAFNOSUPPORT; + return -1; + } + + /* create an 'anonymous' file to have a valid file-descriptor + * which can be close()ed by the caller */ + tmp_fd = mkstemp(tmp_file); + if (tmp_fd < 0) + return -1; + + unlink(tmp_file); + myfd = tmp_fd; + return tmp_fd; +} /* socket */ + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + if (sockfd < 0) { + errno = EBADF; + return -1; + } + + /* we only want to mock UNIX sockets; return an error else */ + if ((addrlen != sizeof(struct sockaddr_un)) || (! addr) + || (! ((const struct sockaddr_un *)addr)->sun_path)) { + errno = EAFNOSUPPORT; + return -1; + } + return 0; +} /* connect */ + +FILE * +fdopen(int fd, const char *mode) +{ + io_cookie_t *cookie; + + if (fd < 0) { + errno = EBADF; + return NULL; + } + + /* check also uses fdopen; in that case we need + * to use the original implementation */ + if (fd != myfd) { + void *libc = dlopen_libc(); + FILE *(*orig_fdopen)(int, const char *); + + orig_fdopen = (FILE *(*)(int, const char *))dlsym(libc, "fdopen"); + + if (! orig_fdopen) + fail("INTERNAL ERROR: failed to load fdopen() from libc"); + + return orig_fdopen(fd, mode); + } + + cookie = calloc(sizeof(*cookie), 1); + if (! cookie) + return NULL; + + cookie->fd = fd; + cookie->pos = 0; + return fopencookie(cookie, mode, mock_io); +} /* fdopen */ + +/* + * private variables + */ + +static sdb_unixsock_client_t *client; + +static void +setup(void) +{ + client = sdb_unixsock_client_create("unixsock_test_path"); + fail_unless(client != NULL, + "sdb_unixsock_client_create() = NULL; " + "expected unixsock client object"); +} /* setup */ + +static void +teardown(void) +{ + sdb_unixsock_client_destroy(client); + client = NULL; +} /* teardown */ + +static void +conn(void) +{ + int check; + + check = sdb_unixsock_client_connect(client); + fail_unless(check == 0, + "sdb_unixsock_client_connect() = %i; expected: 0", check); +} /* conn */ + +/* + * tests + */ + +START_TEST(test_sdb_unixsock_client_create) +{ + sdb_unixsock_client_t *c; + const char *check; + + c = sdb_unixsock_client_create(NULL); + fail_unless(c == NULL, + "sdb_unixsock_client_create() = %p; expected: NULL", c); + + c = sdb_unixsock_client_create("unixsock_test_path"); + fail_unless(c != NULL, + "sdb_unixsock_client_create() = NULL; " + "expected unixsock client object"); + + check = sdb_unixsock_client_path(c); + fail_unless(check != NULL, + "sdb_unixsock_client_create() did not store path name"); + fail_unless(!strcmp(check, "unixsock_test_path"), + "sdb_unixsock_client_create() did not store correct path name; " + "got: '%s'; expected: 'unixsock_test_path'", check); + sdb_unixsock_client_destroy(c); +} +END_TEST + +START_TEST(test_sdb_unixsock_client_connect) +{ + int check; + + check = sdb_unixsock_client_connect(client); + fail_unless(check == 0, + "sdb_unixsock_client_connect() = %i; expected: 0", check); +} +END_TEST + +START_TEST(test_sdb_unixsock_client_send) +{ + size_t i; + + conn(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + int check; + + mock_write_called = 0; + check = sdb_unixsock_client_send(client, golden_data[i].data); + /* client_send appends \r\n */ + fail_unless((size_t)check == golden_data[i].len + 2, + "sdb_unixsock_client_send() = %i; expected: %zu", + check, golden_data[i].len + 2); + fail_unless(mock_write_called == 1, + "sdb_unixsock_client_send() called mock_write %llu times; " + "expected: 1", mock_write_called); + fail_unless(last_write != NULL, + "INTERNAL ERROR: mock_write did not record last write"); + fail_unless((last_write[check - 1] == '\n') + && (last_write[check - 2] == '\r'), + "sdb_unixsock_client_send() did not append \\r\\n " + "before sending; got: '%s'", last_write); + fail_unless(!strncmp(last_write, golden_data[i].data, + (size_t)check - 2), + "sdb_unixsock_client_send() sent unexpected string '%s'; " + "expected: '%s'", last_write, golden_data[i].data); + free(last_write); + last_write = NULL; + } +} +END_TEST + +START_TEST(test_sdb_unixsock_client_recv) +{ + size_t i; + + conn(); + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + char *check; + char buf[64]; + + mock_read_called = 0; + check = sdb_unixsock_client_recv(client, buf, sizeof(buf)); + fail_unless(check != NULL, + "sdb_unixsock_client_recv() = NULL; expected: a string"); + fail_unless(check == buf, + "sdb_unixsock_client_recv() did not return a pointer " + "to the user-provided buffer"); + fail_unless(mock_read_called == 1, + "sdb_unixsock_client_recv() called mock_read %llu times; " + "expected: 1", mock_read_called); + fail_unless(strlen(check) == golden_data[i].len, + "sdb_unixsock_client_recv() returned string of length " + "%zu ('%s'); expected: %zu", + strlen(check), check, golden_data[i].len); + fail_unless(check[golden_data[i].len] != '\n', + "sdb_unixsock_client_recv() did not strip newline"); + fail_unless(!strcmp(check, golden_data[i].data), + "sdb_unixsock_client_recv() = '%s'; expected: '%s'", + check, golden_data[i].data); + } +} +END_TEST + +Suite * +util_unixsock_suite(void) +{ + Suite *s = suite_create("utils::unixsock"); + TCase *tc; + + tc = tcase_create("core"); + tcase_add_checked_fixture(tc, setup, teardown); + tcase_add_test(tc, test_sdb_unixsock_client_create); + tcase_add_test(tc, test_sdb_unixsock_client_connect); + tcase_add_test(tc, test_sdb_unixsock_client_send); + tcase_add_test(tc, test_sdb_unixsock_client_recv); + suite_add_tcase(s, tc); + + return s; +} /* util_unixsock_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/utils/channel_test.c b/t/utils/channel_test.c deleted file mode 100644 index 3827c07..0000000 --- a/t/utils/channel_test.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * SysDB - t/utils/channel_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "utils/channel.h" -#include "libsysdb_test.h" - -#include -#include -#include - -#include - -static struct { - int data; - int expected_write; - int expected_read; -} golden_data_int[] = { - { 5, 0, 0 }, - { 15, 0, 0 }, - { -3, 0, 0 }, - { INT_MAX, 0, 0 }, - { 27, 0, 0 }, - { 42, 0, 0 }, - { 6, 0, 0 }, - { 2854, 0, 0 }, - { 10562, 0, 0 }, - { 0, 0, 0 }, - - /* exceeding buffer size */ - { 20, -1, -1 }, - { 42, -1, -1 }, -}; - -static struct { - char *data; - int expected_write; - int expected_read; -} golden_data_string[] = { - { "c", 0, 0 }, - { "", 0, 0 }, - { "abc", 0, 0 }, - { "foobar", 0, 0 }, - { "qux", 0, 0 }, - { "a b c", 0, 0 }, - { "123", 0, 0 }, - { "xyz", 0, 0 }, - { "b", 0, 0 }, - { "a", 0, 0 }, - - /* exceeding buffer size */ - { "err1", -1, -1 }, - { "err2", -1, -1 }, -}; - -static sdb_channel_t *chan; - -static void -setup_int(void) -{ - chan = sdb_channel_create(10, sizeof(int)); - fail_unless(chan != NULL, - "sdb_channel_create(10, sizeof(int)) = NULL; " - "expected list object"); -} /* setup_int */ - -static void -setup_string(void) -{ - chan = sdb_channel_create(10, sizeof(char *)); - fail_unless(chan != NULL, - "sdb_chan_create(10, sizeof(char *))) = NULL; " - "expected channel object"); -} /* setup_string */ - -static void -teardown(void) -{ - sdb_channel_destroy(chan); - chan = NULL; -} /* teardown */ - -START_TEST(test_create) -{ - chan = sdb_channel_create(0, 0); - fail_unless(chan == NULL, - "sdb_channel_create(0, 0) = %p; expected: NULL", chan); - - chan = sdb_channel_create(0, 1); - fail_unless(chan != NULL, - "sdb_channel_create(0, 1) = NULL; expected: channel object"); - sdb_channel_destroy(chan); - - chan = sdb_channel_create(42, 23); - fail_unless(chan != NULL, - "sdb_channel_create(32, 23) = NULL; expected: channel object"); - sdb_channel_destroy(chan); -} -END_TEST - -START_TEST(test_write_read) -{ - uint32_t data; - int check; - - chan = sdb_channel_create(0, 1); - fail_unless(chan != NULL, - "sdb_channel_create(0, 0) = NULL; expected: channel object"); - - data = 0x00ffff00; - check = sdb_channel_write(chan, &data); - fail_unless(!check, "sdb_channel_write() = %i; expected: 0", check); - check = sdb_channel_write(chan, &data); - fail_unless(check, "sdb_channel_write() = 0; expected: <0"); - - data = 0xffffffff; - check = sdb_channel_read(chan, &data); - fail_unless(check == 0, - "sdb_channel_read() = %d; expected: 0", check); - /* result depends on endianess */ - fail_unless((data == 0xffffff00) || (data == 0x00ffffff), - "sdb_channel_read() returned data %x; " - "expected: 0xffffff00 || 0x00ffffff", data); - - sdb_channel_destroy(chan); -} -END_TEST - -START_TEST(test_select) -{ - struct timespec ts = { 0, 10 }; - int check; - int data; - - chan = sdb_channel_create(0, 1); - - errno = 0; - check = sdb_channel_select(chan, &data, NULL, NULL, NULL, &ts); - fail_unless(check < ETIMEDOUT, - "sdb_channel_select() = %i; expected: <0", check); - fail_unless(errno == ETIMEDOUT, - "sdb_channel_select() set errno to %i; expected: %i (ETIMEDOUT)", - errno, ETIMEDOUT); - - check = sdb_channel_select(chan, NULL, NULL, &data, NULL, NULL); - fail_unless(! check, "sdb_channel_select() = %i; expected: 0", check); - check = sdb_channel_select(chan, NULL, NULL, &data, NULL, &ts); - fail_unless(! check, "sdb_channel_select() = %i; expected: 0", check); - - sdb_channel_destroy(chan); -} -END_TEST - -START_TEST(test_write_int) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { - int data = golden_data_int[i].data; - int expected = golden_data_int[i].expected_write; - - int check = sdb_channel_write(chan, &data); - fail_unless(check == expected, - "sdb_channel_write(chan, %i) = %i; expected: %i", - data, check, expected); - } -} -END_TEST - -START_TEST(test_read_int) -{ - size_t i; - - /* populate */ - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { - int data = golden_data_int[i].data; - int expected = golden_data_int[i].expected_write; - - int check = sdb_channel_write(chan, &data); - fail_unless(check == expected, - "sdb_channel_write(chan, %i) = %i; expected: %i", - data, check, expected); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { - int data = (int)i; - int expected = golden_data_int[i].expected_read; - - int check = sdb_channel_read(chan, &data); - fail_unless(check == expected, - "sdb_channel_read(chan, %i) = %i; expected: %i", - data, check, expected); - if (check) { - fail_unless(data == (int)i, - "sdb_channel_read() modified data to '%i'; " - "expected: no modification", data); - } - else { - fail_unless(data == golden_data_int[i].data, - "sdb_channel_read() returned data %i; expected: %i", - data, golden_data_int[i].data); - } - } -} -END_TEST - -START_TEST(test_write_read_int) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_int); ++i) { - int data = golden_data_int[i].data; - int check = sdb_channel_write(chan, &data); - fail_unless(check == 0, - "sdb_channel_write(chan, %i) = %i; expected: 0", - data, check); - - data = (int)i; - check = sdb_channel_read(chan, &data); - fail_unless(check == 0, - "sdb_channel_read(chan, %i) = %i; expected: 0", - data, check); - if (check) { - fail_unless(data == (int)i, - "sdb_channel_read() modified data to '%i'; " - "expected: no modification", data); - } - else { - fail_unless(data == golden_data_int[i].data, - "sdb_channel_read() returned data %i; expected: %i", - data, golden_data_int[i].data); - } - } -} -END_TEST - -START_TEST(test_write_string) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { - char *data = golden_data_string[i].data; - int expected = golden_data_string[i].expected_write; - - int check = sdb_channel_write(chan, &data); - fail_unless(check == expected, - "sdb_channel_write(chan, '%s') = %i; expected: %i", - data, check, expected); - } -} -END_TEST - -START_TEST(test_read_string) -{ - size_t i; - - /* populate */ - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { - char *data = golden_data_string[i].data; - int expected = golden_data_string[i].expected_write; - - int check = sdb_channel_write(chan, &data); - fail_unless(check == expected, - "sdb_channel_write(chan, '%s') = %i; expected: %i", - data, check, expected); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { - char *data = NULL; - int expected = golden_data_string[i].expected_read; - - int check = sdb_channel_read(chan, &data); - fail_unless(check == expected, - "sdb_channel_read(chan, '') = %i; expected: %i", - check, expected); - if (check) { - fail_unless(data == NULL, - "sdb_channel_read() modified data to '%s'; " - "expected: no modification", data); - } - else { - fail_unless(data != NULL, - "sdb_channel_read() did not return any data"); - fail_unless(!strcmp(data, golden_data_string[i].data), - "sdb_channel_read() returned data '%s'; expected: '%s'", - data, golden_data_string[i].data); - } - } -} -END_TEST - -START_TEST(test_write_read_string) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data_string); ++i) { - char *data = golden_data_string[i].data; - int check = sdb_channel_write(chan, &data); - fail_unless(check == 0, - "sdb_channel_write(chan, '%s') = %i; expected: 0", - data, check); - - data = NULL; - check = sdb_channel_read(chan, &data); - fail_unless(check == 0, - "sdb_channel_read(chan, '') = %i; expected: 0", check); - if (check) { - fail_unless(data == NULL, - "sdb_channel_read() modified data to '%s'; " - "expected: no modifications", data); - } - else { - fail_unless(data != NULL, - "sdb_channel_read() did not return any data"); - fail_unless(!strcmp(data, golden_data_string[i].data), - "sdb_channel_read() returned data '%s'; expected: '%s'", - data, golden_data_string[i].data); - } - } -} -END_TEST - -Suite * -util_channel_suite(void) -{ - Suite *s = suite_create("utils::channel"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_test(tc, test_create); - tcase_add_test(tc, test_write_read); - tcase_add_test(tc, test_select); - suite_add_tcase(s, tc); - - tc = tcase_create("integer"); - tcase_add_checked_fixture(tc, setup_int, teardown); - tcase_add_test(tc, test_write_int); - tcase_add_test(tc, test_read_int); - tcase_add_test(tc, test_write_read_int); - suite_add_tcase(s, tc); - - tc = tcase_create("string"); - tcase_add_checked_fixture(tc, setup_string, teardown); - tcase_add_test(tc, test_write_string); - tcase_add_test(tc, test_read_string); - tcase_add_test(tc, test_write_read_string); - suite_add_tcase(s, tc); - - return s; -} /* util_llist_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/utils/dbi_test.c b/t/utils/dbi_test.c deleted file mode 100644 index 9d45feb..0000000 --- a/t/utils/dbi_test.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * SysDB - t/utils/dbi_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "libsysdb_test.h" -#include "utils/dbi.h" - -#include -#include - -#define TEST_MAGIC ((void *)0x1337) - -/* - * private data-types - */ -typedef union { - long long integer; - double decimal; - const char *string; - time_t datetime; - struct { - size_t length; - const unsigned char *datum; - } binary; -} mock_data_t; - -typedef struct { - const char *name; - unsigned long long nrows; - unsigned long long current_row; - unsigned int nfields; - unsigned short *field_types; - char **field_names; -} mock_query_t; - -/* - * private variables - */ - -static sdb_dbi_client_t *client; - -/* - * mock queries - */ - -/* field definitions */ -static unsigned short field_types[] = { - DBI_TYPE_INTEGER, - DBI_TYPE_DECIMAL, - DBI_TYPE_STRING, - DBI_TYPE_DATETIME, - DBI_TYPE_BINARY, -}; -static char *field_names[] = { - "field0", - "field1", - "field2", - "field3", - "field4", -}; - -#define DATUM(p) ((const unsigned char *)(p)) -static mock_data_t golden_data[][5] = { - { - { .integer = 1234 }, - { .decimal = 1.234 }, - { .string = "abcd" }, - { .datetime = 0 }, - { .binary = { 1, DATUM("a") } }, - }, - { - { .integer = 2345 }, - { .decimal = 23.45 }, - { .string = "bcde" }, - { .datetime = 1 }, - { .binary = { 4, DATUM("bcde") } }, - }, - { - { .integer = 3456 }, - { .decimal = 345.6 }, - { .string = "cd" }, - { .datetime = 2 }, - { .binary = { 0, DATUM(NULL) } }, - }, - { - { .integer = 4567 }, - { .decimal = 4567 }, - { .string = "d" }, - { .datetime = 3 }, - { .binary = { 13, DATUM("defghijklmnop") } }, - }, - { - { .integer = 5678 }, - { .decimal = 56.78 }, - { .string = "efgh" }, - { .datetime = 4 }, - { .binary = { 5, DATUM("efghi") } }, - }, -}; - -/* query definitions */ -static mock_query_t mock_queries[] = { - { "mockquery0", 5, 1, 0, NULL, NULL }, - { "mockquery1", 0, 0, 1, field_types, field_names }, - { "mockquery2", 1, 1, 1, field_types, field_names }, - { "mockquery3", 2, 1, 1, field_types, field_names }, - { "mockquery4", 5, 1, 1, field_types, field_names }, - { "mockquery5", 5, 1, 2, field_types, field_names }, - { "mockquery6", 5, 1, 3, field_types, field_names }, - { "mockquery7", 5, 1, 4, field_types, field_names }, - { "mockquery8", 5, 1, 5, field_types, field_names }, -}; - -static mock_query_t *current_query = NULL; - -/* - * mocked functions - */ - -/* dbi_driver, dbi_conn, dbi_result are void pointers */ - -dbi_driver -dbi_driver_open(const char *name) -{ - if (strcmp(name, "mockdriver")) - return NULL; - return (dbi_driver)strdup(name); -} /* dbi_driver_open */ - -dbi_driver -dbi_driver_list(dbi_driver curr) -{ - if (!curr) - return "mockdriver"; - return NULL; -} /* dbi_driver_list */ - -const char * -dbi_driver_get_name(dbi_driver driver) -{ - return (const char *)driver; -} /* dbi_driver_get_name */ - -int -dbi_conn_set_option(dbi_conn __attribute__((unused)) conn, - const char __attribute__((unused)) *key, - const char __attribute__((unused)) *value) -{ - return 0; -} /* dbi_conn_set_option */ - -const char * -dbi_conn_get_option_list(dbi_conn __attribute__((unused)) conn, - const char __attribute__((unused)) *key) -{ - return NULL; -} /* dbi_conn_get_option_list */ - -dbi_conn -dbi_conn_open(dbi_driver driver) -{ - if (strcmp((const char *)driver, "mockdriver")) - return NULL; - return (dbi_conn)"mockconnection"; -} /* dbi_conn_open */ - -static unsigned long long dbi_conn_connect_called = 0; -int -dbi_conn_connect(dbi_conn conn) -{ - ++dbi_conn_connect_called; - if (strcmp((const char *)conn, "mockconnection")) - return DBI_ERROR_NOCONN; - return 0; -} /* dbi_conn_connect */ - -int -dbi_conn_ping(dbi_conn conn) -{ - if (strcmp((const char *)conn, "mockconnection")) - return 0; - return 1; -} /* dbi_conn_connect */ - -void -dbi_conn_close(dbi_conn __attribute__((unused)) conn) -{ - return; -} /* dbi_conn_close */ - -int -dbi_conn_error(dbi_conn conn, const char **errmsg) -{ - if ((! conn) || (strcmp((const char *)conn, "mockconnection"))) - return DBI_ERROR_BADOBJECT; - if (errmsg) - *errmsg = "mockerror"; - return DBI_ERROR_UNSUPPORTED; -} /* dbi_conn_error */ - -static unsigned long long dbi_conn_query_called = 0; -dbi_result -dbi_conn_query(dbi_conn conn, const char __attribute__((unused)) *statement) -{ - size_t i; - - ++dbi_conn_query_called; - if (strcmp((const char *)conn, "mockconnection")) - return NULL; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { - if (!strcmp(mock_queries[i].name, statement)) { - current_query = &mock_queries[i]; - return (dbi_result)current_query; - } - } - return NULL; -} /* dbi_conn_query */ - -unsigned long long -dbi_result_get_numrows(dbi_result res) -{ - mock_query_t *q = res; - if (! q) - return DBI_ROW_ERROR; - return q->nrows; -} /* dbi_result_get_numrows */ - -unsigned int -dbi_result_get_numfields(dbi_result res) -{ - mock_query_t *q = res; - if (! q) - return DBI_FIELD_ERROR; - return q->nfields; -} /* dbi_result_get_numfields */ - -unsigned short -dbi_result_get_field_type_idx(dbi_result res, unsigned int i) -{ - mock_query_t *q = res; - if ((! q) || (i > q->nfields)) - return DBI_TYPE_ERROR; - return q->field_types[i - 1]; -} /* dbi_result_get_field_type_idx */ - -const char * -dbi_result_get_field_name(dbi_result res, unsigned int i) -{ - mock_query_t *q = res; - if ((! q) || (i > q->nfields)) - return NULL; - return q->field_names[i - 1]; -} /* dbi_result_get_field_name */ - -int -dbi_result_seek_row(dbi_result res, unsigned long long n) -{ - mock_query_t *q = res; - if ((! q) || (n > q->nrows)) - return 0; - - q->current_row = n; - return 1; -} /* dbi_result_seek_row */ - -static mock_data_t -get_golden_data(dbi_result res, unsigned int i) { - mock_query_t *q = res; - fail_unless(q != NULL, "dbi_result_get_*_idx() called with " - "NULL result data; expected valid result object"); - - /* this information is managed by seek_row and, thus, - * should never be invalid */ - fail_unless(q->current_row && q->current_row <= q->nrows, - "INTERNAL ERROR: current row out of range"); - - fail_unless(i && i <= q->nfields, - "dbi_result_get_*_idx() called with index out of range; " - "got: %u; expected [1, %u]", i, q->nfields); - return golden_data[q->current_row - 1][i - 1]; -} /* get_golden_data */ - -long long -dbi_result_get_longlong_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_INTEGER, - "dbi_result_get_longlong_idx() called for non-integer " - "column type %u", current_query->field_types[i - 1]); - return get_golden_data(res, i).integer; -} /* dbi_result_get_longlong_idx */ - -double -dbi_result_get_double_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DECIMAL, - "dbi_result_get_double_idx() called for non-decimal " - "column type %u", current_query->field_types[i - 1]); - return get_golden_data(res, i).decimal; -} /* dbi_result_get_double_idx */ - -const char * -dbi_result_get_string_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING, - "dbi_result_get_string_idx() called for non-string " - "column type %u", current_query->field_types[i - 1]); - return get_golden_data(res, i).string; -} /* dbi_result_get_string_idx */ - -char * -dbi_result_get_string_copy_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING, - "dbi_result_get_string_copy_idx() called for non-string " - "column type %u", current_query->field_types[i - 1]); - if (! get_golden_data(res, i).string) - return NULL; - return strdup(get_golden_data(res, i).string); -} /* dbi_result_get_string_copy_idx */ - -time_t -dbi_result_get_datetime_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DATETIME, - "dbi_result_get_datetime_idx() called for non-datetime " - "column type %u", current_query->field_types[i - 1]); - return get_golden_data(res, i).datetime; -} /* dbi_result_get_datetime_idx */ - -size_t -dbi_result_get_field_length_idx(dbi_result res, unsigned int i) -{ - /* this will check if the parameters are valid */ - get_golden_data(res, i); - - switch (current_query->field_types[i - 1]) { - case DBI_TYPE_INTEGER: - return sizeof(long long); - break; - case DBI_TYPE_DECIMAL: - return sizeof(double); - break; - case DBI_TYPE_STRING: - return strlen(get_golden_data(res, i).string) + 1; - break; - case DBI_TYPE_DATETIME: - return sizeof(time_t); - break; - case DBI_TYPE_BINARY: - return get_golden_data(res, i).binary.length; - break; - } - - fail("INTERNAL ERROR: dbi_result_get_field_length_idx() " - "called for unexpected field type %u", - current_query->field_types[i - 1]); - return 0; -} /* dbi_result_get_field_length_idx */ - -const unsigned char * -dbi_result_get_binary_idx(dbi_result res, unsigned int i) -{ - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY, - "dbi_result_get_binary_idx() called for non-binary " - "column type %u", current_query->field_types[i - 1]); - return get_golden_data(res, i).binary.datum; -} /* dbi_result_get_binary_idx */ - -unsigned char * -dbi_result_get_binary_copy_idx(dbi_result res, unsigned int i) -{ - const char *data; - fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY, - "dbi_result_get_binary_copy_idx() called for non-binary " - "column type %u", current_query->field_types[i - 1]); - data = (const char *)get_golden_data(res, i).binary.datum; - if (! data) - return NULL; - return (unsigned char *)strdup(data); -} /* dbi_result_get_binary_copy_idx */ - -static unsigned long long dbi_result_free_called = 0; -int -dbi_result_free(dbi_result res) -{ - mock_query_t *q = res; - - ++dbi_result_free_called; - if (! q) - return -1; - - current_query = NULL; - return 0; -} /* dbi_result_free */ - -/* - * private helper functions - */ - -static void -setup(void) -{ - client = sdb_dbi_client_create("mockdriver", "mockdatabase"); - fail_unless(client != NULL, - "sdb_dbi_client_create() = NULL; expected client object"); - - dbi_conn_connect_called = 0; -} /* setup */ - -static void -connect(void) -{ - int check = sdb_dbi_client_connect(client); - fail_unless(check == 0, - "sdb_dbi_client_connect() = %i; expected: 0", check); -} /* connect */ - -static void -teardown(void) -{ - sdb_dbi_client_destroy(client); - client = NULL; -} /* teardown */ - -static unsigned long long query_callback_called = 0; -static int -query_callback(sdb_dbi_client_t *c, - size_t n, sdb_data_t *data, sdb_object_t *user_data) -{ - size_t i; - - ++query_callback_called; - - fail_unless(c == client, - "query callback received unexpected client = %p; " - "expected: %p", c, client); - fail_unless(n == current_query->nfields, - "query callback received n = %i; expected: %i", - n, current_query->nfields); - fail_unless(data != NULL, - "query callback received data = NULL; expected: valid data"); - fail_unless(user_data == TEST_MAGIC, - "query callback received user_data = %p; expected: %p", - user_data, TEST_MAGIC); - - for (i = 0; i < n; ++i) { - int expected_type = DBI_TYPE_TO_SC(current_query->field_types[i]); - mock_data_t expected_data; - - fail_unless((int)data[i].type == expected_type, - "query callback received unexpected type %i for " - "column %zu; expected: %i", data[i].type, i, - expected_type); - - expected_data = golden_data[current_query->current_row - 1][i]; - switch (expected_type) { - case SDB_TYPE_INTEGER: - fail_unless(data[i].data.integer == expected_data.integer, - "query callback received unexpected data %lli " - "for column %zu; expected: %lli", - data[i].data.integer, i, expected_data.integer); - break; - case SDB_TYPE_DECIMAL: - fail_unless(data[i].data.decimal == expected_data.decimal, - "query callback received unexpected data %g " - "for column %zu; expected: %g", - data[i].data.decimal, i, expected_data.decimal); - break; - case SDB_TYPE_STRING: - fail_unless(!strcmp(data[i].data.string, expected_data.string), - "query callback received unexpected data %s " - "for column %zu; expected: %s", - data[i].data.string, i, expected_data.string); - break; - case SDB_TYPE_DATETIME: - fail_unless(data[i].data.datetime - == SECS_TO_SDB_TIME(expected_data.datetime), - "query callback received unexpected data "PRIscTIME - " for column %zu; expected: "PRIscTIME, - data[i].data.integer, i, - SECS_TO_SDB_TIME(expected_data.integer)); - break; - case SDB_TYPE_BINARY: - fail_unless(data[i].data.binary.length == - expected_data.binary.length, - "query callback received unexpected " - "binary data length %zu for column %zu; " - "expected: %lli", data[i].data.binary.length, i, - expected_data.binary.length); - fail_unless(!memcmp(data[i].data.binary.datum, - expected_data.binary.datum, - expected_data.binary.length), - "query callback received unexpected binary data %p " - "for column %zu; expected: %p", - data[i].data.binary.datum, i, - expected_data.binary.datum); - break; - default: - fail("INTERNAL ERROR: query callback received " - "unknown type %i for column %zu", - expected_type, i); - } - } - return 0; -} /* query_callback */ - -/* - * tests - */ - -START_TEST(test_sdb_dbi_client_connect) -{ - int check = sdb_dbi_client_connect(client); - fail_unless(check == 0, - "sdb_dbi_client_connect() = %i; expected: 0", check); - - fail_unless(dbi_conn_connect_called == 1, - "sdb_dbi_client_create() called dbi_conn_connect %i times; " - "expected: 1", dbi_conn_connect_called); -} -END_TEST - -START_TEST(test_sdb_dbi_client_check_conn) -{ - int check = sdb_dbi_client_check_conn(client); - fail_unless(check == 0, - "sdb_dbi_client_check_conn() = %i; expected: 0", check); - - /* the first call will actually connect to the database */ - fail_unless(dbi_conn_connect_called == 1, - "sdb_dbi_client_check_conn() called dbi_conn_connect %i times; " - "expected: 1", dbi_conn_connect_called); - - dbi_conn_connect_called = 0; - check = sdb_dbi_client_check_conn(client); - fail_unless(check == 0, - "sdb_dbi_client_check_conn() = %i; expected: 0", check); - - /* should not reconnect */ - fail_unless(dbi_conn_connect_called == 0, - "sdb_dbi_client_check_conn() called dbi_conn_connect %i time(s); " - "expected: 0", dbi_conn_connect_called); -} -END_TEST - -START_TEST(test_sdb_dbi_exec_query) -{ - size_t i; - - int check = sdb_dbi_exec_query(client, "mockquery0", query_callback, - /* user_data = */ TEST_MAGIC, /* n = */ 0); - /* not connected yet */ - fail_unless(check < 0, - "sdb_dbi_exec_query() = %i; expected: < 0", check); - - connect(); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { - mock_query_t *q = &mock_queries[i]; - - unsigned long long expected_callback_calls = 0; - - dbi_conn_query_called = 0; - query_callback_called = 0; - dbi_result_free_called = 0; - - /* sdb_dbi_exec_query will only use as many type arguments are needed, - * so we can safely pass in the maximum number of arguments required - * on each call */ - check = sdb_dbi_exec_query(client, q->name, query_callback, - /* user_data = */ TEST_MAGIC, /* n = */ (int)q->nfields, - SDB_TYPE_INTEGER, SDB_TYPE_DECIMAL, SDB_TYPE_STRING, - SDB_TYPE_DATETIME, SDB_TYPE_BINARY); - fail_unless(check == 0, - "sdb_dbi_exec_query() = %i; expected: 0", check); - - fail_unless(dbi_conn_query_called == 1, - "sdb_dbi_exec_query() called dbi_conn_query %i times; " - "expected: 1", dbi_conn_query_called); - - if (q->nfields) - expected_callback_calls = q->nrows; - - fail_unless(query_callback_called == expected_callback_calls, - "sdb_dbi_exec_query() did not call the registered callback " - "for each result row; got %i call%s; expected: 0", - query_callback_called, - (query_callback_called == 1) ? "" : "s"); - - fail_unless(dbi_result_free_called == 1, - "sdb_dbi_exec_query() did not free the query result object"); - } -} -END_TEST - -/* - * test API - */ - -Suite * -util_dbi_suite(void) -{ - Suite *s = suite_create("utils::dbi"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, setup, teardown); - tcase_add_test(tc, test_sdb_dbi_client_connect); - tcase_add_test(tc, test_sdb_dbi_client_check_conn); - tcase_add_test(tc, test_sdb_dbi_exec_query); - suite_add_tcase(s, tc); - - return s; -} /* util_llist_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/utils/llist_test.c b/t/utils/llist_test.c deleted file mode 100644 index cc9954d..0000000 --- a/t/utils/llist_test.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * SysDB - t/utils/llist_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "utils/llist.h" -#include "libsysdb_test.h" - -#include - -/* - * private data types - */ - -static sdb_object_t golden_data[] = { - SSTRING_OBJ("abc"), - SSTRING_OBJ("bcd"), - SSTRING_OBJ("cde"), - SSTRING_OBJ("def"), - SSTRING_OBJ("efg"), - SSTRING_OBJ("fgh"), - SSTRING_OBJ("ghi") -}; - -static char *unused_names[] = { - "xyz", - "yza", - "zab" -}; - -static sdb_llist_t *list; - -static void -setup(void) -{ - list = sdb_llist_create(); - fail_unless(list != NULL, - "sdb_llist_create() = NULL; expected list object"); -} /* setup */ - -static void -teardown(void) -{ - sdb_llist_destroy(list); - list = NULL; -} /* teardown */ - -/* populate the list with the golden data in the specified order */ -static void -populate(void) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int check = sdb_llist_append(list, &golden_data[i]); - fail_unless(check == 0, - "sdb_llist_append(%s) = %i; expected: 0", - golden_data[i].name, check); - } -} /* populate */ - -START_TEST(test_clone) -{ - sdb_llist_t *clone; - size_t i; - - populate(); - - clone = sdb_llist_clone(list); - fail_unless(clone != NULL, - "sdb_llist_clone() = NULL; expected: cloned list object"); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - fail_unless(golden_data[i].ref_cnt == 3, - "sdb_llist_clone() did not take ownership"); - } - - sdb_llist_destroy(clone); -} -END_TEST - -START_TEST(test_destroy) -{ - size_t i; - populate(); - sdb_llist_destroy(list); - list = NULL; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - fail_unless(golden_data[i].ref_cnt == 1, - "sdb_llist_destroy() did not deref element %s", - golden_data[i].name); - } -} -END_TEST - -START_TEST(test_clear) -{ - size_t i; - populate(); - sdb_llist_clear(list); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - fail_unless(golden_data[i].ref_cnt == 1, - "sdb_llist_clear() did not deref element %s", - golden_data[i].name); - } - - i = sdb_llist_len(list); - fail_unless(i == 0, - "sdb_llist_clear() left %zu elements in the list; " - "expected: 0", i); -} -END_TEST - -START_TEST(test_append) -{ - size_t i; - - fail_unless(sdb_llist_len(list) == 0, - "sdb_llist_len() = %zu; expected: 0", - sdb_llist_len(list)); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int check = sdb_llist_append(list, &golden_data[i]); - fail_unless(check == 0, - "sdb_llist_append(%s) = %i; expected: 0", - golden_data[i].name, check); - fail_unless(golden_data[i].ref_cnt == 2, - "sdb_llist_append(%s) did not take ownership", - golden_data[i].name); - fail_unless(sdb_llist_len(list) == i + 1, - "sdb_llist_len() = %zu; expected: zu", - sdb_llist_len(list), i + 1); - } -} -END_TEST - -START_TEST(test_insert) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int check = sdb_llist_insert(list, &golden_data[i], 0); - fail_unless(check == 0, - "sdb_llist_insert(%s, 0) = %i; expected: 0", - golden_data[i].name, check); - fail_unless(golden_data[i].ref_cnt == 2, - "sdb_llist_insert(%s, 0) did not take ownership", - golden_data[i].name); - } -} -END_TEST - -START_TEST(test_validate_insert) -{ - size_t i; - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - /* none of these operations will succeed - * => 1 is invalid for each case */ - int check = sdb_llist_insert(list, &golden_data[i], 1); - fail_unless(check == -1, - "sdb_llist_insert(%s, 1) = %i; expected: -1", - golden_data[i].name, check); - fail_unless(golden_data[i].ref_cnt == 1, - "sdb_llist_insert(%s, 1) took ownership", - golden_data[i].name); - } -} -END_TEST - -START_TEST(test_get) -{ - size_t i; - populate(); - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_object_t *check = sdb_llist_get(list, i); - fail_unless(check == &golden_data[i], - "sdb_llist_get() = %p; expected: %p", - check, &golden_data[i]); - fail_unless(check->ref_cnt == 3, - "sdb_llist_get() didn't increment reference count; got: %i; " - "expected: 3", check->ref_cnt); - sdb_object_deref(check); - } -} -END_TEST - -START_TEST(test_remove_by_name) -{ - /* "random" indexes */ - int indexes[] = { 4, 5, 3, 6, 2, 0, 1 }; - size_t i; - - populate(); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(indexes); ++i) { - sdb_object_t *check; - - fail_unless((size_t)indexes[i] < SDB_STATIC_ARRAY_LEN(golden_data), - "INTERNAL ERROR: invalid index %i", indexes[i]); - - check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name); - fail_unless(check == &golden_data[indexes[i]], - "sdb_llist_remove_by_name() = %p; expected: %p", - check, &golden_data[indexes[i]]); - fail_unless(check->ref_cnt == 2, - "sdb_llist_remove_by_name() returned unexpected reference " - "count; got: %i; expected: 2", check->ref_cnt); - - check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name); - fail_unless(check == NULL, - "sdb_llist_remove_by_name() did not remove the element"); - } -} -END_TEST - -static int -dummy_lookup(const sdb_object_t __attribute__((unused)) *obj, - const void __attribute__((unused)) *user_data) -{ - return 0; -} /* dummy_lookup */ - -START_TEST(test_search) -{ - size_t i; - populate(); - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_object_t *check = sdb_llist_search_by_name(list, - golden_data[i].name); - fail_unless(check == &golden_data[i], - "sdb_llist_search_by_name(%s) = NULL; expected: %p", - golden_data[i].name, &golden_data[i]); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(unused_names); ++i) { - sdb_object_t *check = sdb_llist_search_by_name(list, - unused_names[i]); - fail_unless(check == NULL, - "sdb_llist_search_by_name(%s) = %p; expected: NULL", - unused_names[i], check); - } - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - /* dummy_lookup always return 0, thus, this will always return the - * first element */ - sdb_object_t *check = sdb_llist_search(list, dummy_lookup, NULL); - fail_unless(check == &golden_data[i], - "sdb_llist_search() = %p (%s); expected: %p (%s)", - check, check->name, &golden_data[i], golden_data[i].name); - - /* => remove the first element */ - check = sdb_llist_remove(list, dummy_lookup, NULL); - fail_unless(check == &golden_data[i], - "sdb_llist_remove() = %p (%s); expected: %p (%s)", - check, check->name, &golden_data[i], golden_data[i].name); - fail_unless(check->ref_cnt == 2, - "sdb_llist_remove() changed reference count; got: %i; " - "expected: 2", check->ref_cnt); - } - /* should now be empty */ - fail_unless(sdb_llist_len(list) == 0, - "Still have %i elements in the list; expected: 0", - sdb_llist_len(list)); -} -END_TEST - -START_TEST(test_shift) -{ - size_t i; - populate(); - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_object_t *check = sdb_llist_shift(list); - fail_unless(check == &golden_data[i], - "sdb_llist_shift() = NULL; expected: %p", - &golden_data[i]); - fail_unless(check->ref_cnt == 2, - "sdb_llist_shift() changed reference count; got: %i; " - "expected: 2", check->ref_cnt); - } - - /* must be empty now */ - fail_unless(sdb_llist_shift(list) == NULL, - "sdb_llist_shift() returned value; expected: NULL"); -} -END_TEST - -START_TEST(test_iter) -{ - sdb_llist_iter_t *iter; - size_t i; - - populate(); - - iter = sdb_llist_get_iter(list); - fail_unless(iter != NULL, - "sdb_llist_get_iter() did not return an iterator"); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_object_t *check; - fail_unless(sdb_llist_iter_has_next(iter), - "sdb_llist_iter_has_next() = FALSE; expected: TRUE"); - check = sdb_llist_iter_get_next(iter); - fail_unless(check == &golden_data[i], - "sdb_llist_iter_get_next() = %p; expected: %p", - check, &golden_data[i]); - } - - fail_unless(!sdb_llist_iter_has_next(iter), - "sdb_llist_iter_has_next() = TRUE; expected: FALSE"); - fail_unless(sdb_llist_iter_get_next(iter) == NULL, - "sdb_llist_iter_get_next() returned value; expected: NULL"); - sdb_llist_iter_destroy(iter); -} -END_TEST - -START_TEST(test_iter_remove) -{ - sdb_llist_iter_t *iter; - sdb_object_t *check; - size_t i; - - populate(); - - iter = sdb_llist_get_iter(list); - fail_unless(iter != NULL, - "sdb_llist_get_iter() did not return an iterator"); - - i = 0; - while (sdb_llist_iter_has_next(iter)) { - check = sdb_llist_iter_get_next(iter); - fail_unless(check == &golden_data[i], - "sdb_llist_iter_get_next() = %p; expected: %p", - check, &golden_data[i]); - - sdb_llist_iter_remove_current(iter); - ++i; - } - sdb_llist_iter_destroy(iter); - - fail_unless(i == (size_t)SDB_STATIC_ARRAY_LEN(golden_data), - "iterated for %zu steps; expected: %i", - i, SDB_STATIC_ARRAY_LEN(golden_data)); - - /* all elements should be removed */ - check = sdb_llist_shift(list); - fail_unless(check == NULL, - "sdb_llist_shift() = %p; expected: NULL", check); -} -END_TEST - -Suite * -util_llist_suite(void) -{ - Suite *s = suite_create("utils::llist"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, setup, teardown); - tcase_add_test(tc, test_clone); - tcase_add_test(tc, test_destroy); - tcase_add_test(tc, test_clear); - tcase_add_test(tc, test_append); - tcase_add_test(tc, test_insert); - tcase_add_test(tc, test_validate_insert); - tcase_add_test(tc, test_get); - tcase_add_test(tc, test_remove_by_name); - tcase_add_test(tc, test_search); - tcase_add_test(tc, test_shift); - tcase_add_test(tc, test_iter); - tcase_add_test(tc, test_iter_remove); - suite_add_tcase(s, tc); - - return s; -} /* util_llist_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/utils/strbuf_test.c b/t/utils/strbuf_test.c deleted file mode 100644 index bb03296..0000000 --- a/t/utils/strbuf_test.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * SysDB - t/utils/strbuf_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "utils/strbuf.h" -#include "libsysdb_test.h" - -#include - -/* - * private data types - */ - -static sdb_strbuf_t *buf; - -static void -setup(void) -{ - buf = sdb_strbuf_create(0); - fail_unless(buf != NULL, - "sdb_strbuf_create() = NULL; expected strbuf object"); -} /* setup */ - -static void -teardown(void) -{ - sdb_strbuf_destroy(buf); - buf = NULL; -} /* teardown */ - -/* - * tests - */ - -START_TEST(test_null) -{ - sdb_strbuf_t *b = NULL; - va_list ap; - - /* check that methods don't crash */ - sdb_strbuf_destroy(b); - sdb_strbuf_skip(b, 0, 0); - sdb_strbuf_skip(b, 0, 10); - sdb_strbuf_skip(b, 10, 10); - sdb_strbuf_clear(b); - - /* check that methods return an error */ - fail_unless(sdb_strbuf_vappend(b, "test", ap) < 0, - "sdb_strbuf_vappend(NULL) didn't report failure"); - fail_unless(sdb_strbuf_append(b, "test") < 0, - "sdb_strbuf_append(NULL) didn't report failure"); - fail_unless(sdb_strbuf_vsprintf(b, "test", ap) < 0, - "sdb_strbuf_vsprintf(NULL) didn't report failure"); - fail_unless(sdb_strbuf_sprintf(b, "test") < 0, - "sdb_strbuf_sprintf(NULL) didn't report failure"); - fail_unless(sdb_strbuf_memcpy(b, "test", 4) < 0, - "sdb_strbuf_memcpy(NULL) didn't report failure"); - fail_unless(sdb_strbuf_memappend(b, "test", 4) < 0, - "sdb_strbuf_memappend(NULL) didn't report failure"); - fail_unless(sdb_strbuf_read(b, 0, 32) < 0, - "sdb_strbuf_read(NULL) didn't report failure"); - fail_unless(sdb_strbuf_chomp(b) < 0, - "sdb_strbuf_chomp(NULL) didn't report failure"); -} -END_TEST - -START_TEST(test_empty) -{ - sdb_strbuf_t *b = sdb_strbuf_create(0); - const char *data; - size_t len; - - /* check that methods don't crash */ - sdb_strbuf_skip(b, 1, 1); - sdb_strbuf_clear(b); - sdb_strbuf_chomp(b); - - data = sdb_strbuf_string(b); - fail_unless(data && (*data == '\0'), - "sdb_strbuf_string() = '%s'; expected: ''", data); - len = sdb_strbuf_len(b); - fail_unless(len == 0, - "sdb_strbuf_len() = %zu; expected: 0", len); - - sdb_strbuf_destroy(b); -} -END_TEST - -START_TEST(test_sdb_strbuf_create) -{ - sdb_strbuf_t *s; - size_t len; - - s = sdb_strbuf_create(0); - fail_unless(s != NULL, - "sdb_strbuf_create() = NULL; expected strbuf object"); - len = sdb_strbuf_len(s); - fail_unless(len == 0, - "sdb_strbuf_create() created buffer with len = %zu; " - "expected: 0", len); - sdb_strbuf_destroy(s); - - s = sdb_strbuf_create(128); - fail_unless(s != NULL, - "sdb_strbuf_create() = NULL; expected strbuf object"); - len = sdb_strbuf_len(s); - /* len still has to be 0 -- there's no content */ - fail_unless(len == 0, - "sdb_strbuf_create() created buffer with len = %zu; " - "expected: 0", len); - sdb_strbuf_destroy(s); -} -END_TEST - -START_TEST(test_sdb_strbuf_append) -{ - ssize_t n, expected; - size_t len; - const char *test; - - n = sdb_strbuf_append(buf, "1234567890"); - fail_unless(n == 10, - "sdb_strbuf_append() appended %zi bytes; expected: 10", n); - len = sdb_strbuf_len(buf); - fail_unless(len == 10, - "sdb_strbuf_append() left behind buffer with len = %zu; " - "expected: 10", len); - - n = sdb_strbuf_append(buf, "ABCDE"); - fail_unless(n == 5, - "sdb_strbuf_append() appended %zi bytes; expected: 5", n); - len = sdb_strbuf_len(buf); - fail_unless(len == 15, - "sdb_strbuf_append() left behind buffer with len = %zu; " - "expected: 15", len); - - test = sdb_strbuf_string(buf); - fail_unless(test[len] == '\0', - "sdb_strbuf_append() did not nil-terminate the string"); - fail_unless(!strcmp(test, "1234567890ABCDE"), - "sdb_strbuf_append() did not correctly concatenate two string; " - "got: %s; expected: 1234567890ABCDE", test); - - n = sdb_strbuf_append(buf, "%zu; %5.4f", len, (double)len / 10.0); - expected = /* len */ 2 + /* "; " */ 2 + /* decimal len/10 */ 6; - fail_unless(n == expected, - "sdb_strbuf_append() appended %zi bytes; expected: %zi", - n, expected); - len = sdb_strbuf_len(buf); - fail_unless(len == 15 + (size_t)expected, - "sdb_strbuf_append() left behind buffer with len = %zu; " - "expected: %zu", len, 15 + (size_t)expected); - - test = sdb_strbuf_string(buf); - fail_unless(test[len] == '\0', - "sdb_strbuf_append() did not nil-terminate the string"); - fail_unless(!strcmp(test, "1234567890ABCDE15; 1.5000"), - "sdb_strbuf_append() did not correctly concatenate two string; " - "got: %s; expected: 1234567890ABCDE15; 1.5000", test); -} -END_TEST - -START_TEST(test_sdb_strbuf_sprintf) -{ - ssize_t n, expected; - size_t len; - const char *test; - - n = sdb_strbuf_sprintf(buf, "1234567890"); - fail_unless(n == 10, - "sdb_strbuf_sprintf() wrote %zi bytes; expected: 10", n); - len = sdb_strbuf_len(buf); - fail_unless(len == 10, - "sdb_strbuf_sprintf() left behind buffer with len = %zu; " - "expected: 10", len); - - n = sdb_strbuf_sprintf(buf, "ABCDE"); - fail_unless(n == 5, - "sdb_strbuf_sprintf() wrote %zi bytes; expected: 5", n); - len = sdb_strbuf_len(buf); - fail_unless(len == 5, - "sdb_strbuf_sprintf() left behind buffer with len = %zu; " - "expected: 5", len); - - test = sdb_strbuf_string(buf); - fail_unless(test[len] == '\0', - "sdb_strbuf_sprintf() did not nil-terminate the string"); - fail_unless(!strcmp(test, "ABCDE"), - "sdb_strbuf_sprintf() did not format string correctly; " - "got: %s; expected: ABCDE", test); - - n = sdb_strbuf_sprintf(buf, "%zu; %5.4f", len, (double)len / 10.0); - expected = /* len */ 1 + /* "; " */ 2 + /* decimal len/10 */ 6; - fail_unless(n == expected, - "sdb_strbuf_sprintf() wrote %zi bytes; expected: %zi", - n, expected); - len = sdb_strbuf_len(buf); - fail_unless(len == (size_t)expected, - "sdb_strbuf_sprintf() left behind buffer with len = %zu; " - "expected: %zu", len, (size_t)expected); - - test = sdb_strbuf_string(buf); - fail_unless(test[len] == '\0', - "sdb_strbuf_sprintf() did not nil-terminate the string"); - fail_unless(!strcmp(test, "5; 0.5000"), - "sdb_strbuf_sprintf() did not format string correctly; " - "got: %s; expected: 5; 0.5000", test); -} -END_TEST - -START_TEST(test_incremental) -{ - ssize_t n; - size_t i; - - sdb_strbuf_destroy(buf); - buf = sdb_strbuf_create(1024); - - /* fill buffer one by one; leave room for nul-byte */ - for (i = 0; i < 1023; ++i) { - n = sdb_strbuf_append(buf, "."); - fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); - } - - /* write another byte; this has to trigger a resize */ - n = sdb_strbuf_append(buf, "."); - fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); - - /* write more bytes; this should trigger at least one more resize but - * that's an implementation detail */ - for (i = 0; i < 1024; ++i) { - n = sdb_strbuf_append(buf, "."); - fail_unless(n == 1, "sdb_strbuf_append() = %zi; expected: 1", n); - } - - n = (ssize_t)sdb_strbuf_len(buf); - fail_unless(n == 2048, "sdb_strbuf_len() = %zi; expectd: 2048", n); -} -END_TEST - -static struct { - const char *input; - size_t size; -} mem_golden_data[] = { - { "abc\0\x10\x42", 6 }, - { "\0\1\2\3\4", 5 }, - { "\n\n\0\n\n", 5 }, - { "", 0 }, -}; - -START_TEST(test_sdb_strbuf_memcpy) -{ - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) { - ssize_t n; - const char *check; - - n = sdb_strbuf_memcpy(buf, mem_golden_data[i].input, - mem_golden_data[i].size); - fail_unless(n >= 0, - "sdb_strbuf_memcpy() = %zi; expected: >=0", n); - fail_unless((size_t)n == mem_golden_data[i].size, - "sdb_strbuf_memcpy() = %zi; expected: %zu", - n, mem_golden_data[i].size); - - n = (ssize_t)sdb_strbuf_len(buf); - fail_unless((size_t)n == mem_golden_data[i].size, - "sdb_strbuf_len() = %zu (after memcpy); expected: %zu", - n, mem_golden_data[i].size); - - check = sdb_strbuf_string(buf); - fail_unless(check != NULL, - "sdb_strbuf_string() = NULL (after memcpy); expected: data"); - fail_unless(check[mem_golden_data[i].size] == '\0', - "sdb_strbuf_memcpy() did not nil-terminate the data"); - fail_unless(!memcmp(check, mem_golden_data[i].input, - mem_golden_data[i].size), - "sdb_strbuf_memcpy() did not set the buffer correctly"); - } -} -END_TEST - -START_TEST(test_sdb_strbuf_memappend) -{ - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(mem_golden_data); ++i) { - ssize_t n; - const char *check; - - size_t total, j; - - n = sdb_strbuf_memappend(buf, mem_golden_data[i].input, - mem_golden_data[i].size); - fail_unless(n >= 0, - "sdb_strbuf_memappend() = %zi; expected: >=0", n); - fail_unless((size_t)n == mem_golden_data[i].size, - "sdb_strbuf_memappend() = %zi; expected: %zu", - n, mem_golden_data[i].size); - - check = sdb_strbuf_string(buf); - fail_unless(check != NULL, - "sdb_strbuf_string() = NULL (after memappend); " - "expected: data"); - - n = (ssize_t)sdb_strbuf_len(buf); - total = 0; - for (j = 0; j <= i; ++j) { - fail_unless(total + mem_golden_data[j].size <= (size_t)n, - "sdb_strbuf_len() = %zu (after memappend); " - "expected: >=%zu", n, total + mem_golden_data[j].size); - - fail_unless(!memcmp(check + total, mem_golden_data[j].input, - mem_golden_data[j].size), - "sdb_strbuf_memappend() did not " - "set the buffer correctly"); - total += mem_golden_data[j].size; - } - fail_unless((size_t)n == total, - "sdb_strbuf_len() = %zu (after memappend); expected: %zu", - n, total); - - fail_unless(check[total] == '\0', - "sdb_strbuf_memappend() did not nil-terminate the data"); - } -} -END_TEST - -static struct { - const char *input; - ssize_t expected; - const char *expected_string; -} chomp_golden_data[] = { - { NULL, 0, "" }, - { "\n", 1, "" }, - { "\n\n", 2, "" }, - { "12345\n\n\n", 3, "12345" }, - { "abcd", 0, "abcd" }, -}; - -START_TEST(test_sdb_strbuf_chomp) -{ - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(chomp_golden_data); ++i) { - ssize_t n; - const char *check; - - if (chomp_golden_data[i].input) - sdb_strbuf_sprintf(buf, chomp_golden_data[i].input); - - /* empty buffer */ - n = sdb_strbuf_chomp(buf); - fail_unless(n == chomp_golden_data[i].expected, - "sdb_strbuf_chomp() = %zi; expected: %zi", n, - chomp_golden_data[i].expected); - - check = sdb_strbuf_string(buf); - fail_unless(!strcmp(check, chomp_golden_data[i].expected_string), - "sdb_strbuf_chomp() did not correctly remove newlines; " - "got string '%s'; expected: '%s'", check, - chomp_golden_data[i].expected_string); - } -} -END_TEST - -/* input is "1234567890" */ -static struct { - size_t offset; - size_t n; - const char *expected; - size_t expected_len; -} skip_golden_data[] = { - { 0, 0, "1234567890", 10 }, - { 0, 1, "234567890", 9 }, - { 0, 2, "34567890", 8 }, - { 0, 9, "0", 1 }, - { 0, 10, "", 0 }, - { 0, 11, "", 0 }, - { 0, 100, "", 0 }, - { 1, 0, "1234567890", 10 }, - { 1, 1, "134567890", 9 }, - { 1, 2, "14567890", 8 }, - { 2, 0, "1234567890", 10 }, - { 2, 1, "124567890", 9 }, - { 2, 2, "12567890", 8 }, - { 2, 3, "1267890", 7 }, - { 2, 4, "127890", 6 }, - { 2, 5, "12890", 5 }, - { 2, 6, "1290", 4 }, - { 2, 7, "120", 3 }, - { 2, 8, "12", 2 }, - { 2, 9, "12", 2 }, - { 2, 10, "12", 2 }, - { 8, 1, "123456780", 9 }, - { 8, 2, "12345678", 8 }, - { 8, 3, "12345678", 8 }, - { 9, 1, "123456789", 9 }, - { 9, 2, "123456789", 9 }, - { 10, 1, "1234567890", 10 }, - { 10, 2, "1234567890", 10 }, -}; - -START_TEST(test_sdb_strbuf_skip) -{ - const char *input = "1234567890"; - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(skip_golden_data); ++i) { - const char *check; - size_t n; - - sdb_strbuf_sprintf(buf, input); - sdb_strbuf_skip(buf, skip_golden_data[i].offset, - skip_golden_data[i].n); - - n = sdb_strbuf_len(buf); - fail_unless(n == skip_golden_data[i].expected_len, - "sdb_strbuf_len() = %zu (after skip); expected: %zu", - n, skip_golden_data[i].expected_len); - - check = sdb_strbuf_string(buf); - fail_unless(!!check, - "sdb_strbuf_string() = NULL (after skip); expected: string"); - - fail_unless(check[n] == '\0', - "sdb_strbuf_skip() did not nil-terminate the string"); - - fail_unless(! strcmp(skip_golden_data[i].expected, check), - "sdb_strbuf_skip('%s', %zu) did not skip correctly; " - "got string '%s'; expected: '%s'", input, - skip_golden_data[i].n, check, skip_golden_data[i].expected); - } -} -END_TEST - -START_TEST(test_sdb_strbuf_clear) -{ - const char *data; - size_t len; - - sdb_strbuf_append(buf, "abc"); - len = sdb_strbuf_len(buf); - fail_unless(len != 0, - "sdb_strbuf_len() = %zu; expected: != 0", len); - - sdb_strbuf_clear(buf); - len = sdb_strbuf_len(buf); - fail_unless(len == 0, - "sdb_strbuf_len() = %zu (after clear); expected: 0", len); - - data = sdb_strbuf_string(buf); - fail_unless(*data == '\0', - "sdb_strbuf_string() = '%s' (after clear); expected: ''", data); -} -END_TEST - -static struct { - const char *input; - const char *expected; -} string_golden_data[] = { - { NULL, "" }, - { "a", "a" }, - { "abcdef", "abcdef" }, -}; - -START_TEST(test_sdb_strbuf_string) -{ - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(string_golden_data); ++i) { - const char *check; - - if (string_golden_data[i].input) - sdb_strbuf_sprintf(buf, string_golden_data[i].input); - check = sdb_strbuf_string(buf); - fail_unless(!strcmp(check, string_golden_data[i].expected), - "sdb_strbuf_string() = '%s'; expected: '%s'", - check, string_golden_data[i].expected); - } -} -END_TEST - -static struct { - const char *input; - size_t expected; -} len_golden_data[] = { - { NULL, 0 }, - { "a", 1 }, - { "12345", 5 }, -}; - -START_TEST(test_sdb_strbuf_len) -{ - size_t i; - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(len_golden_data); ++i) { - size_t check; - - if (len_golden_data[i].input) - sdb_strbuf_sprintf(buf, len_golden_data[i].input); - check = sdb_strbuf_len(buf); - fail_unless(check == len_golden_data[i].expected, - "sdb_strbuf_len() = %zu; expected: %zu", - check, len_golden_data[i].expected); - } -} -END_TEST - -Suite * -util_strbuf_suite(void) -{ - Suite *s = suite_create("utils::strbuf"); - TCase *tc; - - tc = tcase_create("empty"); - tcase_add_test(tc, test_null); - tcase_add_test(tc, test_empty); - suite_add_tcase(s, tc); - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, setup, teardown); - tcase_add_test(tc, test_sdb_strbuf_create); - tcase_add_test(tc, test_sdb_strbuf_append); - tcase_add_test(tc, test_sdb_strbuf_sprintf); - tcase_add_test(tc, test_incremental); - tcase_add_test(tc, test_sdb_strbuf_memcpy); - tcase_add_test(tc, test_sdb_strbuf_memappend); - tcase_add_test(tc, test_sdb_strbuf_chomp); - tcase_add_test(tc, test_sdb_strbuf_skip); - tcase_add_test(tc, test_sdb_strbuf_clear); - tcase_add_test(tc, test_sdb_strbuf_string); - tcase_add_test(tc, test_sdb_strbuf_len); - suite_add_tcase(s, tc); - - return s; -} /* util_strbuf_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ - diff --git a/t/utils/unixsock_test.c b/t/utils/unixsock_test.c deleted file mode 100644 index 4502767..0000000 --- a/t/utils/unixsock_test.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * SysDB - t/utils/unixsock_test.c - * Copyright (C) 2013 Sebastian 'tokkee' Harl - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -/* required for fopencookie support */ -#define _GNU_SOURCE - -#include "utils/unixsock.h" -#include "libsysdb_test.h" - -#include - -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include - -/* - * I/O "hook" functions - */ - -typedef struct { - int fd; - size_t pos; -} io_cookie_t; - -static struct { - const char *data; - size_t len; -} golden_data[] = { - { "a", 1 }, - { "abc", 3 }, - { "12345", 5 }, - { "", 0 }, -}; - -static char *last_write = NULL; - -static unsigned long long mock_read_called = 0; -static ssize_t -mock_read(void *cookie, char *buf, size_t size) -{ - io_cookie_t *c = cookie; - ssize_t ret; - - ++mock_read_called; - - if (c->pos >= SDB_STATIC_ARRAY_LEN(golden_data)) - return 0; - - ret = snprintf(buf, size, "%s\n", golden_data[c->pos].data); - ++c->pos; - return ret; -} /* mock_read */ - -static unsigned long long mock_write_called = 0; -static ssize_t -mock_write(void *cookie, const char *buf, size_t size) -{ - io_cookie_t *c = cookie; - - ++mock_write_called; - - if (c->pos >= SDB_STATIC_ARRAY_LEN(golden_data)) - return 0; - - if (last_write) - free(last_write); - last_write = strdup(buf); - ++c->pos; - return (ssize_t)size; -} /* mock_write */ - -/* unsupported: int seek(void *cookie, off64_t *offset, int whence) */ - -static int -mock_close(void *cookie) -{ - io_cookie_t *c = cookie; - - if (! c) - return EBADF; - - close(c->fd); - free(c); - return 0; -} /* mock_close */ - -static cookie_io_functions_t mock_io = { - /* read = */ mock_read, - /* write = */ mock_write, - /* seek = */ NULL, - /* close = */ mock_close, -}; - -/* - * mocked functions - */ - -static int myfd = -1; - -static void * -dlopen_libc(void) -{ - static void *libc = NULL; - - if (libc) - return libc; - - libc = dlopen("libc.so.6", RTLD_LAZY); - if (! libc) - fail("INTERNAL ERROR: failed to load libc"); - return libc; -} /* dlopen_libc */ - -int -socket(int domain, int __attribute__((unused)) type, - int __attribute__((unused)) protocol) -{ - char tmp_file[] = "unixsock_test_socket.XXXXXX"; - int tmp_fd; - - /* we only want to mock UNIX sockets; return an error else */ - if (domain != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } - - /* create an 'anonymous' file to have a valid file-descriptor - * which can be close()ed by the caller */ - tmp_fd = mkstemp(tmp_file); - if (tmp_fd < 0) - return -1; - - unlink(tmp_file); - myfd = tmp_fd; - return tmp_fd; -} /* socket */ - -int -connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - if (sockfd < 0) { - errno = EBADF; - return -1; - } - - /* we only want to mock UNIX sockets; return an error else */ - if ((addrlen != sizeof(struct sockaddr_un)) || (! addr) - || (! ((const struct sockaddr_un *)addr)->sun_path)) { - errno = EAFNOSUPPORT; - return -1; - } - return 0; -} /* connect */ - -FILE * -fdopen(int fd, const char *mode) -{ - io_cookie_t *cookie; - - if (fd < 0) { - errno = EBADF; - return NULL; - } - - /* check also uses fdopen; in that case we need - * to use the original implementation */ - if (fd != myfd) { - void *libc = dlopen_libc(); - FILE *(*orig_fdopen)(int, const char *); - - orig_fdopen = (FILE *(*)(int, const char *))dlsym(libc, "fdopen"); - - if (! orig_fdopen) - fail("INTERNAL ERROR: failed to load fdopen() from libc"); - - return orig_fdopen(fd, mode); - } - - cookie = calloc(sizeof(*cookie), 1); - if (! cookie) - return NULL; - - cookie->fd = fd; - cookie->pos = 0; - return fopencookie(cookie, mode, mock_io); -} /* fdopen */ - -/* - * private variables - */ - -static sdb_unixsock_client_t *client; - -static void -setup(void) -{ - client = sdb_unixsock_client_create("unixsock_test_path"); - fail_unless(client != NULL, - "sdb_unixsock_client_create() = NULL; " - "expected unixsock client object"); -} /* setup */ - -static void -teardown(void) -{ - sdb_unixsock_client_destroy(client); - client = NULL; -} /* teardown */ - -static void -conn(void) -{ - int check; - - check = sdb_unixsock_client_connect(client); - fail_unless(check == 0, - "sdb_unixsock_client_connect() = %i; expected: 0", check); -} /* conn */ - -/* - * tests - */ - -START_TEST(test_sdb_unixsock_client_create) -{ - sdb_unixsock_client_t *c; - const char *check; - - c = sdb_unixsock_client_create(NULL); - fail_unless(c == NULL, - "sdb_unixsock_client_create() = %p; expected: NULL", c); - - c = sdb_unixsock_client_create("unixsock_test_path"); - fail_unless(c != NULL, - "sdb_unixsock_client_create() = NULL; " - "expected unixsock client object"); - - check = sdb_unixsock_client_path(c); - fail_unless(check != NULL, - "sdb_unixsock_client_create() did not store path name"); - fail_unless(!strcmp(check, "unixsock_test_path"), - "sdb_unixsock_client_create() did not store correct path name; " - "got: '%s'; expected: 'unixsock_test_path'", check); - sdb_unixsock_client_destroy(c); -} -END_TEST - -START_TEST(test_sdb_unixsock_client_connect) -{ - int check; - - check = sdb_unixsock_client_connect(client); - fail_unless(check == 0, - "sdb_unixsock_client_connect() = %i; expected: 0", check); -} -END_TEST - -START_TEST(test_sdb_unixsock_client_send) -{ - size_t i; - - conn(); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - int check; - - mock_write_called = 0; - check = sdb_unixsock_client_send(client, golden_data[i].data); - /* client_send appends \r\n */ - fail_unless((size_t)check == golden_data[i].len + 2, - "sdb_unixsock_client_send() = %i; expected: %zu", - check, golden_data[i].len + 2); - fail_unless(mock_write_called == 1, - "sdb_unixsock_client_send() called mock_write %llu times; " - "expected: 1", mock_write_called); - fail_unless(last_write != NULL, - "INTERNAL ERROR: mock_write did not record last write"); - fail_unless((last_write[check - 1] == '\n') - && (last_write[check - 2] == '\r'), - "sdb_unixsock_client_send() did not append \\r\\n " - "before sending; got: '%s'", last_write); - fail_unless(!strncmp(last_write, golden_data[i].data, - (size_t)check - 2), - "sdb_unixsock_client_send() sent unexpected string '%s'; " - "expected: '%s'", last_write, golden_data[i].data); - free(last_write); - last_write = NULL; - } -} -END_TEST - -START_TEST(test_sdb_unixsock_client_recv) -{ - size_t i; - - conn(); - - for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - char *check; - char buf[64]; - - mock_read_called = 0; - check = sdb_unixsock_client_recv(client, buf, sizeof(buf)); - fail_unless(check != NULL, - "sdb_unixsock_client_recv() = NULL; expected: a string"); - fail_unless(check == buf, - "sdb_unixsock_client_recv() did not return a pointer " - "to the user-provided buffer"); - fail_unless(mock_read_called == 1, - "sdb_unixsock_client_recv() called mock_read %llu times; " - "expected: 1", mock_read_called); - fail_unless(strlen(check) == golden_data[i].len, - "sdb_unixsock_client_recv() returned string of length " - "%zu ('%s'); expected: %zu", - strlen(check), check, golden_data[i].len); - fail_unless(check[golden_data[i].len] != '\n', - "sdb_unixsock_client_recv() did not strip newline"); - fail_unless(!strcmp(check, golden_data[i].data), - "sdb_unixsock_client_recv() = '%s'; expected: '%s'", - check, golden_data[i].data); - } -} -END_TEST - -Suite * -util_unixsock_suite(void) -{ - Suite *s = suite_create("utils::unixsock"); - TCase *tc; - - tc = tcase_create("core"); - tcase_add_checked_fixture(tc, setup, teardown); - tcase_add_test(tc, test_sdb_unixsock_client_create); - tcase_add_test(tc, test_sdb_unixsock_client_connect); - tcase_add_test(tc, test_sdb_unixsock_client_send); - tcase_add_test(tc, test_sdb_unixsock_client_recv); - suite_add_tcase(s, tc); - - return s; -} /* util_unixsock_suite */ - -/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ -