From: Sebastian Harl Date: Tue, 10 Dec 2013 19:29:28 +0000 (+0100) Subject: Merged branch 'master' of git://git.tokkee.org/sysdb. X-Git-Tag: sysdb-0.1.0~314 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=ddb7ffc175e49abfa69c82777b88d73e1f1103fb;hp=50f0c90249b043acd6dd72979a319f81f2e48f74 Merged branch 'master' of git://git.tokkee.org/sysdb. --- diff --git a/src/core/store.c b/src/core/store.c index 8f5cae3..e9e0979 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -418,11 +418,15 @@ sdb_store_attribute(const char *hostname, const char *key, const char *value, /* stored object = */ SDB_ATTRIBUTE, key, last_update, &updated_attr); - SDB_ATTR(updated_attr)->value = strdup(value); - if (! SDB_ATTR(updated_attr)->value) { - sdb_object_deref(SDB_OBJ(updated_attr)); - status = -1; + if (status >= 0) { + assert(updated_attr); + SDB_ATTR(updated_attr)->value = strdup(value); + if (! SDB_ATTR(updated_attr)->value) { + sdb_object_deref(SDB_OBJ(updated_attr)); + status = -1; + } } + pthread_rwlock_unlock(&obj_lock); return status; } /* sdb_store_attribute */ @@ -533,7 +537,7 @@ sdb_store_tojson(sdb_strbuf_t *buf) } sdb_llist_iter_destroy(svc_iter); - sdb_strbuf_append(buf, "]}"); + sdb_strbuf_append(buf, "]},"); } sdb_strbuf_append(buf, "]}"); diff --git a/t/Makefile.am b/t/Makefile.am index c31ac50..87140cf 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -7,6 +7,7 @@ check_PROGRAMS = libsysdb_test libsysdb_net_test libsysdb_test_SOURCES = \ libsysdb_test.c libsysdb_test.h \ core/object_test.c \ + core/store_test.c \ utils/channel_test.c \ utils/dbi_test.c \ utils/llist_test.c \ diff --git a/t/core/object_test.c b/t/core/object_test.c index f5b7bf6..e00d300 100644 --- a/t/core/object_test.c +++ b/t/core/object_test.c @@ -52,30 +52,44 @@ obj_destroy_noop(sdb_object_t *obj) fail_unless(obj != NULL, "obj destroy function: received obj == NULL"); } /* obj_destroy_noop */ -START_TEST(test_obj_create) +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) { - struct noop { - sdb_object_t super; - int data; - }; - sdb_type_t noop_type = { - /* size = */ sizeof(struct noop), - /* init = */ obj_init_noop, - /* destroy = */ obj_destroy_noop, - }; + ++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, noop_type); + obj = sdb_object_create(name, test_type); fail_unless(obj != NULL, "sdb_object_create() = NULL; expected: a new object"); - fail_unless(obj->type.size == noop_type.size, + fail_unless(obj->type.size == test_type.size, "after sdb_object_create(): type size mismatch; got: %zu; " - "expected: %zu", obj->type.size, noop_type.size); + "expected: %zu", obj->type.size, test_type.size); fail_unless(obj->ref_cnt == 1, "after sdb_object_create(): obj->ref_cnt = %d; expected: 1", obj->ref_cnt); @@ -104,7 +118,7 @@ START_TEST(test_obj_create) init_noop_called = 0; init_noop_retval = -1; destroy_noop_called = 0; - obj = sdb_object_create(name, noop_type); + obj = sdb_object_create(name, test_type); fail_unless(obj == NULL, "sdb_object_create() = %p; expected NULL (init returned -1)", obj); @@ -114,11 +128,11 @@ START_TEST(test_obj_create) "sdb_object_create() did not call object's destroy function " "after init failure"); - noop_type.size = 1; + test_type.size = 1; init_noop_called = 0; init_noop_retval = 0; destroy_noop_called = 0; - obj = sdb_object_create(name, noop_type); + obj = sdb_object_create(name, test_type); fail_unless(obj == NULL, "sdb_object_create() = %p; expected NULL (type's size too small)", obj); @@ -129,22 +143,157 @@ START_TEST(test_obj_create) "sdb_object_create() called object's destroy function " "when size was too small"); - noop_type.size = sizeof(struct noop); + test_type.size = sizeof(struct noop); init_noop_retval = 0; - noop_type.init = NULL; - obj = sdb_object_create(name, noop_type); + 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); - noop_type.destroy = NULL; - obj = sdb_object_create(name, noop_type); + 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); } 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(obj->ref_cnt <= 0, + "after db_object_deref(): obj->ref_cnt = %d; expected: <= 0", + 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 == 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) { @@ -153,6 +302,9 @@ core_object_suite(void) 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; diff --git a/t/core/store_test.c b/t/core/store_test.c new file mode 100644 index 0000000..afc5323 --- /dev/null +++ b/t/core/store_test.c @@ -0,0 +1,235 @@ +/* + * 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 "libsysdb_test.h" + +#include +#include + +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_attr) +{ + struct { + const char *host; + const char *key; + const 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) { + int status; + + status = sdb_store_attribute(golden_data[i].host, + golden_data[i].key, golden_data[i].value, + 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_attribute(%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 + +START_TEST(test_store_tojson) +{ + sdb_strbuf_t *buf; + + int status, pos; + size_t len1, len2; + size_t i; + + const char *expected = "{\"hosts\":[" + "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"attributes\": [" + "{\"name\": \"k1\", \"value\": \"v1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}," + "{\"name\": \"k2\", \"value\": \"v2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}," + "{\"name\": \"k3\", \"value\": \"v3\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}," + "], " + "\"services\": []}," + "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", " + "\"attributes\": [], " + "\"services\": [" + "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}," + "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}," + "]}," + "]}"; + + sdb_store_host("h1", 1); + sdb_store_host("h2", 1); + + sdb_store_attribute("h1", "k1", "v1", 1); + sdb_store_attribute("h1", "k2", "v2", 1); + sdb_store_attribute("h1", "k3", "v3", 1); + + sdb_store_service("h2", "s1", 1); + sdb_store_service("h2", "s2", 1); + + buf = sdb_strbuf_create(0); + status = sdb_store_tojson(buf); + fail_unless(status == 0, + "sdb_store_tojson() = %d; expected: 0", status); + + 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() returned unexpected result\n" + " got: %s\n %*s\n expected: %s", + sdb_strbuf_string(buf), pos + 1, "^", expected); +} +END_TEST + +Suite * +core_store_suite(void) +{ + Suite *s = suite_create("core::store"); + TCase *tc; + + tc = tcase_create("core"); + /* test this first to ensure the store is empty + * even when using CK_NOFORK */ + tcase_add_test(tc, test_store_tojson); + tcase_add_test(tc, test_store_host); + tcase_add_test(tc, test_store_attr); + tcase_add_test(tc, test_store_service); + suite_add_tcase(s, tc); + + return s; +} /* core_store_suite */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/libsysdb_net_test.c b/t/libsysdb_net_test.c index aede0d6..320cfac 100644 --- a/t/libsysdb_net_test.c +++ b/t/libsysdb_net_test.c @@ -33,6 +33,7 @@ #include #include +#include int main(void) @@ -48,6 +49,8 @@ main(void) #endif /* HAVE_FOPENCOOKIE */ }; + putenv("TZ=UTC"); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(creators); ++i) { SRunner *sr; Suite *s; diff --git a/t/libsysdb_test.c b/t/libsysdb_test.c index 91909b8..ca2a22d 100644 --- a/t/libsysdb_test.c +++ b/t/libsysdb_test.c @@ -29,6 +29,7 @@ #include #include +#include int main(void) @@ -38,12 +39,15 @@ main(void) suite_creator_t creators[] = { { core_object_suite, NULL }, + { core_store_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; diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h index eadeca5..f9fddeb 100644 --- a/t/libsysdb_test.h +++ b/t/libsysdb_test.h @@ -63,6 +63,10 @@ typedef struct { Suite * core_object_suite(void); +/* t/core/store_test */ +Suite * +core_store_suite(void); + /* t/utils/channel_test */ Suite * util_channel_suite(void);