From: Sebastian Harl Date: Fri, 31 Jan 2014 06:27:24 +0000 (+0100) Subject: Merged branch 'master' of git://git.tokkee.org/sysdb. X-Git-Tag: sysdb-0.1.0~226 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=3cc3e3c36239c902263678100180c95c8263f7f8;hp=3dfbb8002ceb61be3cb61a7764c98fef4b6c011a Merged branch 'master' of git://git.tokkee.org/sysdb. --- diff --git a/configure.ac b/configure.ac index ac28122..5cae366 100644 --- a/configure.ac +++ b/configure.ac @@ -254,11 +254,15 @@ AC_ARG_WITH([libdbi], [AS_HELP_STRING([--with-libdbi], [libdbi support (default: auto)])], [with_libdbi="$withval"], [with_libdbi="yes"]) -if test "x$with_libdbi" = "xyes"; then +if test "x$with_libdbi" = "xyes" || test "x$with_libdbi" = "xauto"; then AC_CHECK_HEADERS([dbi/dbi.h], [with_libdbi="yes"], [with_libdbi="no (dbi/dbi.h not found)"]) -fi +else if test "x$with_libdbi" = "xno"; then + with_libdbi="$with_libdbi (disabled on command-line)" +else + AC_MSG_ERROR([Invalid value for option --with-libdbi=$with_libdbi (expected "yes", "no", or "auto")]) +fi; fi if test "x$with_libdbi" = "xyes"; then AC_CHECK_LIB([dbi], [dbi_initialize], [with_libdbi="yes"], @@ -287,7 +291,12 @@ AC_ARG_WITH([readline], if test "x$readline_support" = "xyes"; then readline_support="auto" -fi +else if test "x$readline_support" != "xauto" \ + && test "x$readline_support" != "xno" \ + && test "x$readline_support" != "xlibedit" \ + && test "x$readline_support" != "xlibreadline"; then + AC_MSG_ERROR([Invalid value for option --with-readline=$readline_support (expected "yes", "no", "auto", "libedit", or "libreadline")]) +fi; fi have_libedit="no" if test "x$readline_support" = "xauto" \ @@ -395,10 +404,14 @@ AC_SDB_PLUGIN([mk-livestatus], [yes], [backend accessing Nagios/Icinga/Shinken using MK Livestatus]) AC_SDB_PLUGIN([puppet-storeconfigs], [$puppet_storeconfigs_default], [backend accessing the Puppet stored configuration database]) -AC_SDB_PLUGIN([syslog], [yes], - [plugin logging to syslog]) + +m4_divert_once([HELP_ENABLE], [ +Plugins:]) + AC_SDB_PLUGIN([cname-dns], [yes], [canonicalize hostnames by querying DNS]) +AC_SDB_PLUGIN([syslog], [yes], + [plugin logging to syslog]) AM_CONDITIONAL([BUILD_DOCUMENTATION], test "x$build_documentation" = "xyes") AM_CONDITIONAL([BUILD_TESTING], test "x$build_testing" = "xyes") @@ -442,6 +455,7 @@ AC_MSG_RESULT([ puppet-storeconfigs: . . . $enable_puppet_storeconfigs]) AC_MSG_RESULT() AC_MSG_RESULT([ Plugins:]) AC_MSG_RESULT([ cname::dns: . . . . . . . . $enable_cname_dns]) +AC_MSG_RESULT([ syslog: . . . . . . . . . . $enable_syslog]) AC_MSG_RESULT() AC_MSG_RESULT([This package is maintained by $PACKAGE_MAINTAINER.]) AC_MSG_RESULT([Please report bugs to $PACKAGE_BUGREPORT.]) diff --git a/src/Makefile.am b/src/Makefile.am index 9206e27..8736948 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,7 +66,7 @@ libsysdb_la_SOURCES = \ core/object.c include/core/object.h \ core/plugin.c include/core/plugin.h \ core/store.c include/core/store.h \ - include/core/data.h \ + core/data.c include/core/data.h \ frontend/connection.c include/frontend/connection.h \ frontend/connection-private.h \ frontend/parser.c include/frontend/parser.h \ @@ -129,6 +129,14 @@ pkgbackendcollectdlib_LTLIBRARIES = pkgbackendpuppetlib_LTLIBRARIES = pkgcnamelib_LTLIBRARIES = +if BUILD_PLUGIN_CNAMEDNS +pkgcnamelib_LTLIBRARIES += plugins/cname/dns.la +plugins_cname_dns_la_SOURCE = plugins/cname/dns.c +plugins_cname_dns_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version +libsysdb_la_LIBADD += -dlopen plugins/cname/dns.la +libsysdb_la_DEPENDENCIES += plugins/cname/dns.la +endif + if BUILD_PLUGIN_COLLECTD pkgbackendcollectdlib_LTLIBRARIES += backend/collectd/unixsock.la backend_collectd_unixsock_la_SOURCES = backend/collectd/unixsock.c @@ -161,14 +169,6 @@ libsysdb_la_LIBADD += -dlopen plugins/syslog.la libsysdb_la_DEPENDENCIES += plugins/syslog.la endif -if BUILD_PLUGIN_CNAMEDNS -pkgcnamelib_LTLIBRARIES += plugins/cname/dns.la -plugins_cname_dns_la_SOURCE = plugins/cname/dns.c -plugins_cname_dns_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version -libsysdb_la_LIBADD += -dlopen plugins/cname/dns.la -libsysdb_la_DEPENDENCIES += plugins/cname/dns.la -endif - include/client/sysdb.h: include/client/sysdb.h.in ../version source ../version; sed \ -e "s/@SDB_VERSION_MAJOR@/$$VERSION_MAJOR/g" \ diff --git a/src/backend/puppet/store-configs.c b/src/backend/puppet/store-configs.c index a9a0ff7..e109b30 100644 --- a/src/backend/puppet/store-configs.c +++ b/src/backend/puppet/store-configs.c @@ -87,7 +87,7 @@ sdb_puppet_stcfg_get_attrs(sdb_dbi_client_t __attribute__((unused)) *client, const char *hostname; const char *key; - const char *value; + sdb_data_t value; sdb_time_t last_update; assert(n == 4); @@ -98,10 +98,11 @@ sdb_puppet_stcfg_get_attrs(sdb_dbi_client_t __attribute__((unused)) *client, hostname = data[0].data.string; key = data[1].data.string; - value = data[2].data.string; + value.type = SDB_TYPE_STRING; + value.data.string = data[2].data.string; last_update = data[3].data.datetime; - status = sdb_store_attribute(hostname, key, value, last_update); + status = sdb_store_attribute(hostname, key, &value, last_update); if (status < 0) { sdb_log(SDB_LOG_ERR, "puppet::store-configs backend: Failed to " diff --git a/src/client/sock.c b/src/client/sock.c index 49cefdf..59c7787 100644 --- a/src/client/sock.c +++ b/src/client/sock.c @@ -230,14 +230,14 @@ sdb_client_recv(sdb_client_t *client, size_t data_offset = sdb_strbuf_len(buf); + if (code) + *code = UINT32_MAX; + if ((! client) || (! client->fd) || (! buf)) { errno = EBADF; return -1; } - if (code) - *code = UINT32_MAX; - while (42) { ssize_t status; diff --git a/src/core/data.c b/src/core/data.c new file mode 100644 index 0000000..1bb5400 --- /dev/null +++ b/src/core/data.c @@ -0,0 +1,133 @@ +/* + * SysDB - src/core/data.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 + +#include +#include + +/* + * public API + */ + +int +sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src) +{ + sdb_data_t tmp; + + if ((! dst) || (! src)) + return -1; + + tmp = *src; + switch (src->type) { + case SDB_TYPE_STRING: + tmp.data.string = strdup(src->data.string); + if (! tmp.data.string) + return -1; + break; + case SDB_TYPE_BINARY: + tmp.data.binary.datum = malloc(src->data.binary.length); + if (! tmp.data.binary.datum) + return -1; + memcpy(tmp.data.binary.datum, src->data.binary.datum, + src->data.binary.length); + break; + } + + *dst = tmp; + return 0; +} /* sdb_data_copy */ + +void +sdb_data_free_datum(sdb_data_t *datum) +{ + if (! datum) + return; + + switch (datum->type) { + case SDB_TYPE_STRING: + if (datum->data.string) + free(datum->data.string); + datum->data.string = NULL; + break; + case SDB_TYPE_BINARY: + if (datum->data.binary.datum) + free(datum->data.binary.datum); + datum->data.binary.datum = NULL; + datum->data.binary.length = 0; + break; + } +} /* sdb_data_free_datum */ + +int +sdb_data_format(sdb_data_t *datum, sdb_strbuf_t *buf) +{ + if ((! datum) || (! buf)) + return -1; + + switch (datum->type) { + case SDB_TYPE_INTEGER: + sdb_strbuf_append(buf, "%"PRIi64, datum->data.integer); + break; + case SDB_TYPE_DECIMAL: + sdb_strbuf_append(buf, "%a", datum->data.decimal); + break; + case SDB_TYPE_STRING: + /* TODO: escape special characters */ + sdb_strbuf_append(buf, "\"%s\"", datum->data.string); + break; + case SDB_TYPE_DATETIME: + { + char tmp[64]; + if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z", + datum->data.datetime)) + return -1; + tmp[sizeof(tmp) - 1] = '\0'; + sdb_strbuf_append(buf, "%s", tmp); + } + break; + case SDB_TYPE_BINARY: + { + size_t i; + /* TODO: improve this! */ + sdb_strbuf_append(buf, "%s", "\""); + for (i = 0; i < datum->data.binary.length; ++i) + sdb_strbuf_append(buf, "\\%x", + (int)datum->data.binary.datum[i]); + sdb_strbuf_append(buf, "%s", "\""); + } + break; + default: + return -1; + } + return 0; +} /* sdb_data_format */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/core/store.c b/src/core/store.c index e8d14a0..2522233 100644 --- a/src/core/store.c +++ b/src/core/store.c @@ -71,7 +71,7 @@ struct sdb_store_base { typedef struct { sdb_store_base_t super; - char *value; + sdb_data_t value; } sdb_attribute_t; #define SDB_ATTR(obj) ((sdb_attribute_t *)(obj)) #define SDB_CONST_ATTR(obj) ((const sdb_attribute_t *)(obj)) @@ -158,20 +158,19 @@ sdb_store_obj_destroy(sdb_object_t *obj) static int sdb_attr_init(sdb_object_t *obj, va_list ap) { - const char *value; + const sdb_data_t *value; int ret; - /* this will consume the first argument (type) of ap */ + /* this will consume the first two arguments + * (type and last_update) of ap */ ret = store_base_init(obj, ap); if (ret) return ret; - value = va_arg(ap, const char *); + value = va_arg(ap, const sdb_data_t *); - if (value) { - SDB_ATTR(obj)->value = strdup(value); - if (! SDB_ATTR(obj)->value) + if (value) + if (sdb_data_copy(&SDB_ATTR(obj)->value, value)) return -1; - } return 0; } /* sdb_attr_init */ @@ -181,9 +180,7 @@ sdb_attr_destroy(sdb_object_t *obj) assert(obj); store_base_destroy(obj); - - if (SDB_ATTR(obj)->value) - free(SDB_ATTR(obj)->value); + sdb_data_free_datum(&SDB_ATTR(obj)->value); } /* sdb_attr_destroy */ static sdb_type_t sdb_store_obj_type = { @@ -416,8 +413,9 @@ store_obj_tojson(sdb_llist_t *list, int type, sdb_strbuf_t *buf) sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(sobj)->name); if (type == SDB_ATTRIBUTE) + /* XXX: this needs to be type-dependent */ sdb_strbuf_append(buf, "\"value\": \"%s\", ", - SDB_ATTR(sobj)->value); + SDB_ATTR(sobj)->value.data.string); sdb_strbuf_append(buf, "\"last_update\": \"%s\"}", time_str); if (sdb_llist_iter_has_next(iter)) @@ -477,7 +475,8 @@ sdb_store_get_host(const char *name) } /* sdb_store_get_host */ int -sdb_store_attribute(const char *hostname, const char *key, const char *value, +sdb_store_attribute(const char *hostname, + const char *key, const sdb_data_t *value, sdb_time_t last_update) { int status; @@ -494,8 +493,7 @@ sdb_store_attribute(const char *hostname, const char *key, const char *value, if (status >= 0) { assert(updated_attr); - SDB_ATTR(updated_attr)->value = strdup(value); - if (! SDB_ATTR(updated_attr)->value) { + if (sdb_data_copy(&SDB_ATTR(updated_attr)->value, value)) { sdb_object_deref(SDB_OBJ(updated_attr)); status = -1; } diff --git a/src/include/core/data.h b/src/include/core/data.h index 4a4dd2d..58e92cd 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -29,6 +29,7 @@ #define SDB_CORE_DATA_H 1 #include "core/time.h" +#include "utils/strbuf.h" #include #include @@ -48,25 +49,57 @@ enum { /* * sdb_data_t: * A datum retrieved from an arbitrary data source. - * - * The string and binary objects are managed by whoever creates the data - * object, thus, they must not be freed or modified. If you want to keep them, - * make sure to make a copy. */ typedef struct { int type; union { int64_t integer; /* SDB_TYPE_INTEGER */ double decimal; /* SDB_TYPE_DECIMAL */ - const char *string; /* SDB_TYPE_STRING */ + char *string; /* SDB_TYPE_STRING */ sdb_time_t datetime; /* SDB_TYPE_DATETIME */ struct { size_t length; - const unsigned char *datum; + unsigned char *datum; } binary; /* SDB_TYPE_BINARY */ } data; } sdb_data_t; +/* + * sdb_data_copy: + * Copy the datum stored in 'src' to the memory location pointed to by 'dst'. + * Any dynamic data (strings, binary data) is copied to newly allocated + * memory. Use, for example, sdb_data_free_datum() to free any dynamic memory + * stored in a datum. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src); + +/* + * sdb_data_free_datum: + * Free any dynamic memory referenced by the specified datum. Does not free + * the memory allocated for the sdb_data_t object itself. This function must + * not be used if any static or stack memory is referenced from the data + * object. + */ +void +sdb_data_free_datum(sdb_data_t *datum); + +/* + * sdb_data_format: + * Append the specified datum to the specified string buffer using a default + * format. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_data_format(sdb_data_t *datum, sdb_strbuf_t *buf); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/include/core/store.h b/src/include/core/store.h index ab11a21..100aadf 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -30,6 +30,7 @@ #include "sysdb.h" #include "core/object.h" +#include "core/data.h" #include "core/time.h" #include "utils/llist.h" #include "utils/strbuf.h" @@ -95,7 +96,8 @@ sdb_store_get_host(const char *name); * - a negative value on error */ int -sdb_store_attribute(const char *hostname, const char *key, const char *value, +sdb_store_attribute(const char *hostname, + const char *key, const sdb_data_t *value, sdb_time_t last_update); /* diff --git a/src/tools/sysdb/command.c b/src/tools/sysdb/command.c index 30e6419..f948d3a 100644 --- a/src/tools/sysdb/command.c +++ b/src/tools/sysdb/command.c @@ -33,8 +33,11 @@ #include "tools/sysdb/input.h" #include "frontend/proto.h" +#include "utils/error.h" #include "utils/strbuf.h" +#include + #include #include #include @@ -66,6 +69,7 @@ sdb_command_exec(sdb_input_t *input) if (query_len) { sdb_strbuf_t *recv_buf; + const char *result; uint32_t rcode = 0; recv_buf = sdb_strbuf_create(1024); @@ -81,7 +85,13 @@ sdb_command_exec(sdb_input_t *input) if (rcode == UINT32_MAX) printf("ERROR: "); - printf("%s\n", sdb_strbuf_string(recv_buf)); + result = sdb_strbuf_string(recv_buf); + if (result && *result) + printf("%s\n", result); + else if (rcode == UINT32_MAX) { + char errbuf[1024]; + printf("%s\n", sdb_strerror(errno, errbuf, sizeof(errbuf))); + } sdb_strbuf_destroy(recv_buf); } diff --git a/src/utils/dbi.c b/src/utils/dbi.c index 1de2f1a..a30f548 100644 --- a/src/utils/dbi.c +++ b/src/utils/dbi.c @@ -84,7 +84,7 @@ sdb_dbi_get_field(dbi_result res, unsigned int i, data->data.decimal = dbi_result_get_double_idx(res, i); break; case SDB_TYPE_STRING: - data->data.string = dbi_result_get_string_idx(res, i); + data->data.string = dbi_result_get_string_copy_idx(res, i); break; case SDB_TYPE_DATETIME: { @@ -96,7 +96,7 @@ sdb_dbi_get_field(dbi_result res, unsigned int i, case SDB_TYPE_BINARY: { size_t length = dbi_result_get_field_length_idx(res, i); - const unsigned char *datum = dbi_result_get_binary_idx(res, i); + unsigned char *datum = dbi_result_get_binary_copy_idx(res, i); data->data.binary.length = length; data->data.binary.datum = datum; } @@ -141,6 +141,8 @@ sdb_dbi_get_data(sdb_dbi_client_t *client, dbi_result res, return -1; for (n = 0; n < num_rows; ++n) { + int status; + if (! dbi_result_seek_row(res, n + 1)) { sdb_log(SDB_LOG_ERR, "dbi: Failed to retrieve row %llu: %s", n, sdb_dbi_strerror(client->conn)); @@ -152,7 +154,11 @@ sdb_dbi_get_data(sdb_dbi_client_t *client, dbi_result res, types[i], &data[i])) continue; - if (callback(client, num_fields, data, user_data)) + status = callback(client, num_fields, data, user_data); + for (i = 0; i < num_fields; ++i) + sdb_data_free_datum(&data[i]); + + if (status) continue; ++success; diff --git a/src/utils/unixsock.c b/src/utils/unixsock.c index 62b6f45..9a5c3fa 100644 --- a/src/utils/unixsock.c +++ b/src/utils/unixsock.c @@ -113,7 +113,7 @@ sdb_unixsock_parse_cell(char *string, int type, sdb_data_t *data) case SDB_TYPE_BINARY: /* we don't support any binary information containing 0-bytes */ data->data.binary.length = strlen(string); - data->data.binary.datum = (const unsigned char *)string; + data->data.binary.datum = (unsigned char *)string; break; default: sdb_log(SDB_LOG_ERR, "unixsock: Unexpected type %i while " diff --git a/t/Makefile.am b/t/Makefile.am index 6adf484..3c13ad5 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -10,6 +10,7 @@ check_PROGRAMS = libsysdb_test libsysdb_net_test libsysdb_test_SOURCES = \ libsysdb_test.c libsysdb_test.h \ + core/data_test.c \ core/object_test.c \ core/store_test.c \ frontend/parser_test.c \ diff --git a/t/core/data_test.c b/t/core/data_test.c new file mode 100644 index 0000000..fb3b114 --- /dev/null +++ b/t/core/data_test.c @@ -0,0 +1,200 @@ +/* + * 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) +{ + sdb_data_t datum; + sdb_strbuf_t *buf; + const char *string; + const char *expected; + + int check; + + buf = sdb_strbuf_create(1024); + fail_unless(buf != NULL, + "INTERNAL ERROR: Failed to allocate string buffer"); + + datum.type = SDB_TYPE_INTEGER; + datum.data.integer = 4711; + check = sdb_data_format(&datum, buf); + fail_unless(! check, + "sdb_data_format(INTEGER) = %d; expected: 0", check); + string = sdb_strbuf_string(buf); + expected = "4711"; + fail_unless(! strcmp(string, expected), + "sdb_data_format() used wrong format: %s; expected: %s", + string, expected); + + datum.type = SDB_TYPE_DECIMAL; + datum.data.decimal = 65536.0; + sdb_strbuf_clear(buf); + check = sdb_data_format(&datum, buf); + fail_unless(! check, + "sdb_data_format(DECIMAL) = %d; expected: 0", check); + string = sdb_strbuf_string(buf); + expected = "0x1p+16"; + fail_unless(! strcmp(string, expected), + "sdb_data_format() used wrong format: %s; expected: %s", + string, expected); + + datum.type = SDB_TYPE_STRING; + datum.data.string = "this is a test"; + sdb_strbuf_clear(buf); + check = sdb_data_format(&datum, buf); + fail_unless(! check, + "sdb_data_format(STRING) = %d; expected: 0", check); + string = sdb_strbuf_string(buf); + expected = "\"this is a test\""; + fail_unless(! strcmp(string, expected), + "sdb_data_format() used wrong format: %s; expected: %s", + string, expected); + + datum.type = SDB_TYPE_DATETIME; + datum.data.datetime = 471147114711471100; + sdb_strbuf_clear(buf); + check = sdb_data_format(&datum, buf); + fail_unless(! check, + "sdb_data_format(DATETIME) = %d; expected: 0", check); + string = sdb_strbuf_string(buf); + expected = "1984-12-06 02:11:54 +0000"; + fail_unless(! strcmp(string, expected), + "sdb_data_format() used wrong format: %s; expected: %s", + string, expected); + + datum.type = SDB_TYPE_BINARY; + datum.data.binary.datum = (unsigned char *)"binary\0crap\x42"; + datum.data.binary.length = 12; + sdb_strbuf_clear(buf); + check = sdb_data_format(&datum, buf); + fail_unless(! check, + "sdb_data_format(BINARY) = %d; expected: 0", check); + string = sdb_strbuf_string(buf); + expected = "\"\\62\\69\\6e\\61\\72\\79\\0\\63\\72\\61\\70\\42\""; + fail_unless(! strcmp(string, expected), + "sdb_data_format() used wrong format: %s; expected: %s", + string, expected); +} +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/store_test.c b/t/core/store_test.c index effd05a..855c8c0 100644 --- a/t/core/store_test.c +++ b/t/core/store_test.c @@ -147,7 +147,7 @@ START_TEST(test_store_attr) struct { const char *host; const char *key; - const char *value; + char *value; sdb_time_t last_update; int expected; } golden_data[] = { @@ -166,10 +166,15 @@ START_TEST(test_store_attr) 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, golden_data[i].value, + 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", @@ -244,6 +249,7 @@ verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags) START_TEST(test_store_tojson) { sdb_strbuf_t *buf; + sdb_data_t datum; size_t i; struct { @@ -296,9 +302,13 @@ START_TEST(test_store_tojson) 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); + 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); diff --git a/t/libsysdb_test.c b/t/libsysdb_test.c index 2fa83dc..c7787e4 100644 --- a/t/libsysdb_test.c +++ b/t/libsysdb_test.c @@ -38,6 +38,7 @@ main(void) size_t i; suite_creator_t creators[] = { + { core_data_suite, NULL }, { core_object_suite, NULL }, { core_store_suite, NULL }, { fe_parser_suite, NULL }, diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h index 64558cd..5539d63 100644 --- a/t/libsysdb_test.h +++ b/t/libsysdb_test.h @@ -59,6 +59,10 @@ typedef struct { * test suites */ +/* t/core/data_test */ +Suite * +core_data_suite(void); + /* t/core/object_test */ Suite * core_object_suite(void); diff --git a/t/utils/dbi_test.c b/t/utils/dbi_test.c index 10447e9..c54ea31 100644 --- a/t/utils/dbi_test.c +++ b/t/utils/dbi_test.c @@ -331,6 +331,17 @@ dbi_result_get_string_idx(dbi_result res, unsigned int i) 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) { @@ -379,6 +390,19 @@ dbi_result_get_binary_idx(dbi_result res, unsigned int i) 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) @@ -467,7 +491,7 @@ query_callback(sdb_dbi_client_t *c, data[i].data.decimal, i, expected_data.decimal); break; case SDB_TYPE_STRING: - fail_unless(data[i].data.string == expected_data.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); @@ -487,8 +511,9 @@ query_callback(sdb_dbi_client_t *c, "binary data length %zu for column %zu; " "expected: %lli", data[i].data.binary.length, i, expected_data.binary.length); - fail_unless(data[i].data.binary.datum == + 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,