diff --git a/Makefile.am b/Makefile.am index ec1f202..3edb4ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS=libdroplet examples +SUBDIRS=libdroplet examples utests pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = droplet-3.0.pc diff --git a/configure.ac b/configure.ac index 248bedd..66f5578 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,7 @@ AC_CONFIG_FILES([ Makefile examples/Makefile libdroplet/Makefile +utests/Makefile droplet-3.0.pc libdroplet.spec ]) diff --git a/libdroplet/include/droplet/ntinydb.h b/libdroplet/include/droplet/ntinydb.h index ebceede..1aa278f 100644 --- a/libdroplet/include/droplet/ntinydb.h +++ b/libdroplet/include/droplet/ntinydb.h @@ -37,7 +37,7 @@ typedef int (*dpl_ntinydb_func_t)(const char *key_ptr, int key_len, void *cb_arg); /* PROTO ntinydb.c */ -dpl_status_t dpl_ntinydb_set(dpl_sbuf_t *blob, const char *key, char *buf, int len); +dpl_status_t dpl_ntinydb_set(dpl_sbuf_t *blob, const char *key, const char *buf, int len); dpl_status_t dpl_ntinydb_get(const char *buf, int len, const char *key, const char **data_returned, int *datalen_returned); dpl_status_t dpl_ntinydb_list(const char *buf, int len, dpl_ntinydb_func_t cb_func, void *cb_arg); #endif diff --git a/libdroplet/src/dict.c b/libdroplet/src/dict.c index 33de1bc..a6bda29 100644 --- a/libdroplet/src/dict.c +++ b/libdroplet/src/dict.c @@ -97,6 +97,9 @@ dpl_dict_new(int n_buckets) { dpl_dict_t *dict; + if (0 == n_buckets) + return NULL; + dict = malloc(sizeof (*dict)); if (NULL == dict) return NULL; diff --git a/libdroplet/src/ntinydb.c b/libdroplet/src/ntinydb.c index 2a01948..f383740 100644 --- a/libdroplet/src/ntinydb.c +++ b/libdroplet/src/ntinydb.c @@ -48,7 +48,7 @@ dpl_status_t dpl_ntinydb_set(dpl_sbuf_t *blob, const char *key, - char *data, + const char *data, int datalen) { char flag; diff --git a/utests/Makefile.am b/utests/Makefile.am new file mode 100644 index 0000000..d342d4f --- /dev/null +++ b/utests/Makefile.am @@ -0,0 +1,6 @@ +bin_PROGRAMS = alltests + +alltests_CFLAGS = -std=gnu99 -I$(top_srcdir)/libdroplet/include +alltests_LDADD = $(top_builddir)/libdroplet/libdroplet.la $(JSON_LIBS) -lcrypto -lcheck +alltests_SOURCES = taskpool_utest.c ntinydb_utest.c dbuf_utest.c sbuf_utest.c dict_utest.c vec_utest.c utest_main.c + diff --git a/utests/dbuf_utest.c b/utests/dbuf_utest.c new file mode 100644 index 0000000..6a86543 --- /dev/null +++ b/utests/dbuf_utest.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include "utest_main.h" + +START_TEST(dbuf_test) +{ + dpl_dbuf_t * b = dpl_dbuf_new(); + fail_if(NULL == b, NULL); + fail_unless(0 == dpl_dbuf_length(b), NULL); + dpl_dbuf_free(b); + + b = dpl_dbuf_new(); + fail_if(NULL == b, NULL); + + const char * str = "abcdefghijklmnopqrstuvwxyz"; + int ret; + + ret = dpl_dbuf_add(b, str, sizeof(str)); + fail_unless(1 == ret, NULL); + fail_unless(sizeof(str) == dpl_dbuf_length(b), NULL); + + unsigned int i; + for (i = 0; i < sizeof(str); i++) + { + char out; + ret = dpl_dbuf_consume(b, &out, sizeof(out)); + fail_unless(1 == ret, NULL); + fail_unless(sizeof(str) == dpl_dbuf_length(b) + i + 1, NULL); + fail_unless(out == str[i], NULL); + } + dpl_dbuf_free(b); +} +END_TEST + + + Suite * +dbuf_suite () +{ + Suite * s = suite_create("dbuf"); + TCase * t = tcase_create("base"); + tcase_add_test(t, dbuf_test); + suite_add_tcase(s, t); + return s; +} diff --git a/utests/dict_utest.c b/utests/dict_utest.c new file mode 100644 index 0000000..91eb322 --- /dev/null +++ b/utests/dict_utest.c @@ -0,0 +1,120 @@ +#include +#include + +#include "utest_main.h" + + +static int +utest_dpl_dict_dump_one(dpl_dict_var_t * v, void *user_data) +{ + fail_unless(user_data == NULL, NULL); + fail_if(NULL == v, NULL); + fail_unless(v->val->type == DPL_VALUE_STRING, NULL); + printf("%s: %s\n", v->key, v->val->string->buf); + + return 0; +} + +START_TEST(dict_test) +{ + dpl_dict_t * dict; + const char * const * it; + char init_value[] = "a"; + dpl_dict_var_t * var; + const dpl_value_t * value; + dpl_status_t ret; + int c; + + static const char * const utest_strings[] = { "Foo", "bAr", "baz", NULL }; + + dict = dpl_dict_new(0); + fail_unless(NULL == dict, NULL); + dict = dpl_dict_new(10); + + it = utest_strings; + while (*it != NULL) + { + ret = dpl_dict_add(dict, *it, init_value, 1); + fail_unless(DPL_SUCCESS == ret, NULL); + (*init_value)++; + it++; + } + // + // new, free, dup, copy combo + // + dpl_dict_t * d2 = dpl_dict_new(5); + ret = dpl_dict_copy(d2, dict); + fail_unless(DPL_SUCCESS == ret, NULL); + dpl_dict_free(dict); + dict = dpl_dict_new(20); + ret = dpl_dict_copy(dict, d2); + fail_unless(DPL_SUCCESS == ret, NULL); + dpl_dict_free(d2); + d2 = dpl_dict_dup(dict); + fail_unless(NULL != d2, NULL); + dpl_dict_free(dict); + dict = d2; + + it = utest_strings; + var = dpl_dict_get(dict, *it); + fail_unless(var == NULL, NULL); + it++; + var = dpl_dict_get(dict, *it); + fail_unless(var == NULL, NULL); + it++; + var = dpl_dict_get(dict, *it); + fail_if(NULL == var, NULL); + value = var->val; + fail_unless(DPL_VALUE_STRING == value->type, NULL); + fail_unless(0 == strcmp(value->string->buf, "c"), NULL); + + it = utest_strings; + dpl_dict_get_lowered(dict, *it, &var); + fail_if(NULL == var, NULL); + value = var->val; + fail_unless(DPL_VALUE_STRING == value->type, NULL); + fail_unless(0 == strcmp(value->string->buf, "a"), NULL); + it++; + dpl_dict_get_lowered(dict, *it, &var); + fail_if(NULL == value, NULL); + value = var->val; + fail_unless(DPL_VALUE_STRING == value->type, NULL); + fail_unless(0 == strcmp(value->string->buf, "b"), NULL); + it++; + dpl_dict_get_lowered(dict, *it, &var); + fail_if(NULL == value, NULL); + value = var->val; + fail_unless(DPL_VALUE_STRING == value->type, NULL); + fail_unless(0 == strcmp(value->string->buf, "c"), NULL); + + dpl_dict_iterate(dict, utest_dpl_dict_dump_one, NULL); + dpl_dict_print(dict, stdout, 0); + + c = dpl_dict_count(dict); + fail_unless(3 == c, NULL); + +#if 0 + dpl_dict_var_free(); + dpl_dict_add_value(); + dpl_dict_remove(); + dpl_dict_dup(); + dpl_dict_filter_prefix(); + dpl_dict_get_value(); +#endif + + dpl_dict_free(dict); +} +END_TEST + + + Suite * +dict_suite (void) +{ + Suite * s = suite_create("dict"); + TCase * d = tcase_create("base"); + tcase_add_test(d, dict_test); + suite_add_tcase(s, d); + return s; +} + + diff --git a/utests/ntinydb_utest.c b/utests/ntinydb_utest.c new file mode 100644 index 0000000..376b587 --- /dev/null +++ b/utests/ntinydb_utest.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utest_main.h" + +typedef struct { + unsigned int nelem; + const char ** keys; + bool * found; +} arg_list; + +static int check_keys (const char * k, + int kl, + void * arg) +{ + arg_list * a = (arg_list*) arg; + unsigned int i; + for (i = 0; i < a->nelem; i++) + { + if (0 == strncmp(k, a->keys[i], kl)) + { + a->found[i] = true; + break; + } + } + return 0; +} + + +START_TEST(ntinydb_test) +{ + dpl_sbuf_t * b = dpl_sbuf_new(1); + const char * keys[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}; + char * datas[sizeof(keys) / sizeof(keys[0])]; + unsigned int i; + int fd; + int ret; + dpl_status_t s; + + fd = open("/dev/urandom", O_RDONLY); + fail_if(-1 == ret, NULL); + + for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) + { + datas[i] = malloc(512); + fail_if(NULL == datas[i], NULL); + ret = read(fd, datas[i], 512); + fail_unless(512 == ret, NULL); + s = dpl_ntinydb_set(b, keys[i], datas[i], 512); + fail_unless(DPL_SUCCESS == s, NULL); + } + for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) + { + const char * datas_check[sizeof(keys) / sizeof(keys[0])]; + int out_len; + s = dpl_ntinydb_get(b->buf, b->len, keys[i], datas_check + i, &out_len); + fail_unless(DPL_SUCCESS == s, NULL); + fail_unless(512 == out_len); + fail_unless(0 == memcmp(datas_check[i], datas[i], 512)); + } + arg_list all_keys; + all_keys.nelem = sizeof(keys) / sizeof(keys[0]); + all_keys.keys = keys; + all_keys.found = malloc(sizeof(bool) * all_keys.nelem); + for (i = 0; i < all_keys.nelem; i++) + { + all_keys.found[i] = false; + } + + s = dpl_ntinydb_list(b->buf, b->len, check_keys, &all_keys); + fail_unless(DPL_SUCCESS == s, NULL); + for (i = 0; i < all_keys.nelem; i++) + { + fail_if(false == all_keys.found[i], NULL); + } +} +END_TEST + + + Suite * +ntinydb_suite (void) +{ + Suite * s = suite_create("ntinydb"); + TCase * d = tcase_create("base"); + tcase_add_test(d, ntinydb_test); + suite_add_tcase(s, d); + return s; +} + diff --git a/utests/sbuf_utest.c b/utests/sbuf_utest.c new file mode 100644 index 0000000..4aa0506 --- /dev/null +++ b/utests/sbuf_utest.c @@ -0,0 +1,60 @@ +#include +#include +#include + + +START_TEST(sbuf_test) +{ + dpl_sbuf_t * b; + dpl_sbuf_t * b2; + + int sizes[] = { 1, 2, 4, 8, 16, 32, 65}; + unsigned int i; + for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) + { + b = dpl_sbuf_new(sizes[i]); + fail_if(NULL == b, NULL); + b2 = dpl_sbuf_dup(b); + fail_if(NULL == b2, NULL); + dpl_sbuf_free(b); + dpl_sbuf_free(b2); + } + + const char * strs[] = { "truc", "bidule", "machin", "chose" }; + for (i = 0; i < sizeof(strs) / sizeof(strs[0]); i++) + { + b = dpl_sbuf_new_from_str(strs[i]); + fail_if(NULL == b, NULL); + fail_unless(0 == strcmp(strs[i], dpl_sbuf_get_str(b)), NULL); + b2 = dpl_sbuf_dup(b); + fail_if(NULL == b2, NULL); + fail_unless(0 == strcmp(strs[i], dpl_sbuf_get_str(b2)), NULL); + dpl_sbuf_print(stdout, b); + dpl_sbuf_free(b); + dpl_sbuf_free(b2); + } + + const char * full_str = "trucbidulemachinchose"; + b = dpl_sbuf_new_from_str(""); + for (i = 0; i < sizeof(strs) / sizeof(strs[0]); i++) + { + dpl_status_t ret; + ret = dpl_sbuf_add_str(b, strs[i]); + fail_unless(DPL_SUCCESS == ret, NULL); + } + fail_unless(0 == strcmp(full_str, dpl_sbuf_get_str(b)), NULL); + dpl_sbuf_free(b); + puts(""); +} +END_TEST + + + Suite * +sbuf_suite () +{ + Suite * s = suite_create("sbuf"); + TCase * t = tcase_create("base"); + tcase_add_test(t, sbuf_test); + suite_add_tcase(s, t); + return s; +} diff --git a/utests/taskpool_utest.c b/utests/taskpool_utest.c new file mode 100644 index 0000000..47151ce --- /dev/null +++ b/utests/taskpool_utest.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include + +#include "utest_main.h" + + +// +// Retrieve a fake ctx for task pool initialization +// + static dpl_ctx_t * +get_ctx (void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + static dpl_ctx_t t; + + void init (void) + { + bzero(&t, sizeof(t)); + pthread_mutex_init(&t.lock, NULL); + return; + } + (void) pthread_once(&once, init); + return &t; +} + + +START_TEST(taskpool_test) +{ + dpl_task_pool_t * p; + p = dpl_task_pool_create(get_ctx(), "taskpool_test", 100); + fail_if(NULL == p); + dpl_task_pool_destroy(p); + + p = dpl_task_pool_create(get_ctx(), "taskpool_test", 100); + fail_if(NULL == p); + dpl_task_pool_cancel(p); + + p = dpl_task_pool_create(get_ctx(), "taskpool_test", 100); + fail_if(NULL == p); + // + // Increase and decrease the number of workers + // + int wn[] = { 1, 100, 50, 200, 100}; + for (unsigned int i = 0; i < sizeof(wn) / sizeof(wn[0]); i++) + { + int ret; + ret = dpl_task_pool_set_workers(p, wn[i]); + fail_unless(0 == ret, NULL); + usleep(100000); // give a chance to the threads to stop themselves + ret = dpl_task_pool_get_workers(p); + fail_unless(wn[i] == ret, "Fail at loop iteration %d: expected workers %d, retrieved workers %d", i, wn[i], ret); + } + + // + // Start thread, wait, and cancel combo + // + static int incr = 0; + static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + void * tf (void * arg) + { + unsigned int i = 0; + for (i = 0; i < 10000; i++) + { + pthread_mutex_lock(&mtx); + incr++; + pthread_mutex_unlock(&mtx); + } + return NULL; + } + + dpl_task_t * tasks = calloc(1000, sizeof(*tasks)); + fail_if(NULL == tasks, NULL); + for (unsigned int i = 0; i < 100; i++) + { + tasks[i].func = tf; + dpl_task_pool_put(p, &tasks[i]); + } + dpl_task_pool_wait_idle(p); + fail_unless(100 * 10000 == incr, NULL); + + incr = 0; + for (unsigned int i = 0; i < 100; i++) + { + tasks[i].func = tf; + dpl_task_pool_put(p, &tasks[i]); + } + dpl_task_pool_cancel(p); + fail_unless(100 * 10000 == incr, NULL); + dpl_task_pool_destroy(p); +} +END_TEST + + + Suite * +taskpool_suite () +{ + Suite * s = suite_create("taskpool"); + TCase * t = tcase_create("base"); + tcase_add_test(t, taskpool_test); + suite_add_tcase(s, t); + return s; +} diff --git a/utests/utest_main.c b/utests/utest_main.c new file mode 100644 index 0000000..a7e50ca --- /dev/null +++ b/utests/utest_main.c @@ -0,0 +1,21 @@ +#include +#include + +#include "utest_main.h" + + + int +main (int argc, + char ** argv) +{ + SRunner * r = srunner_create(dict_suite()); + srunner_add_suite(r, vec_suite()); + srunner_add_suite(r, sbuf_suite()); + srunner_add_suite(r, dbuf_suite()); + srunner_add_suite(r, ntinydb_suite()); + srunner_add_suite(r, taskpool_suite()); + srunner_run_all(r, CK_NORMAL); + int number_failed = srunner_ntests_failed(r); + srunner_free(r); + return (0 == number_failed) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/utests/utest_main.h b/utests/utest_main.h new file mode 100644 index 0000000..749fd20 --- /dev/null +++ b/utests/utest_main.h @@ -0,0 +1,11 @@ +#ifndef __UTEST_MAIN_H__ +#define __UTEST_MAIN_H__ + +extern Suite * dict_suite (void); +extern Suite * vec_suite (void); +extern Suite * sbuf_suite (void); +extern Suite * dbuf_suite (void); +extern Suite * ntinydb_suite (void); +extern Suite * taskpool_suite (void); + +#endif diff --git a/utests/vec_utest.c b/utests/vec_utest.c new file mode 100644 index 0000000..c41dbb5 --- /dev/null +++ b/utests/vec_utest.c @@ -0,0 +1,73 @@ +#include +#include + +static int reverse_sort (const void * a, const void * b) +{ + unsigned int x = (unsigned int) a; + unsigned int y = (unsigned int) b; + + return (x == y) ? 0 : (x < y ? 1 : -1); +} + + +START_TEST(vec_test) +{ + unsigned int i, j; + dpl_vec_t * v, * v2; + dpl_status_t ret; + + v = dpl_vec_new(0, 0); + fail_unless(NULL == v, NULL); + + v = dpl_vec_new(100, 10); + fail_if(NULL == v, NULL); + dpl_vec_free(v); + + int ics[] = {0, 10}; + for (i = 0; i < sizeof(ics) / sizeof(ics[0]); i++) + { + v = dpl_vec_new(1, ics[i]); + for (j = 0; j < 1000; j++) + { + ret = dpl_vec_add(v, (void*)j); + fail_unless(DPL_SUCCESS == ret, NULL); + } + v2 = dpl_vec_dup(v); + for (j = 0; j < 1000; j++) + { + unsigned int t; + t = (unsigned int) dpl_vec_get(v2, j); + fail_unless((unsigned int) t == j, NULL); + } + dpl_vec_print(v, stdout, 0); + puts(""); + dpl_vec_free(v); + dpl_vec_free(v2); + } + + v = dpl_vec_new(1000, 0); + for (i = 0; i < 1000; i++) + { + ret = dpl_vec_add(v, (void*) i); + fail_unless(DPL_SUCCESS == ret, NULL); + } + dpl_vec_sort(v, reverse_sort); + for (i = 0; i < 1000; i++) + { + j = (unsigned int) dpl_vec_get(v, i); + fail_unless(j == (1000 - 1 - i), NULL); + } +} +END_TEST + + + Suite * +vec_suite (void) +{ + Suite * s = suite_create("vec"); + TCase * t = tcase_create("base"); + tcase_add_test(t, vec_test); + suite_add_tcase(s, t); + return s; +} +