From 3d6b8b306cdbd4ec15b36a1e7936d219204e08dc Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 24 May 2018 17:14:42 +0200 Subject: [PATCH] krb5 locator: add unit tests Unit test for existing and new functionality of the Kerberos locator plugin. Related to https://pagure.io/SSSD/sssd/issue/941 Reviewed-by: Jakub Hrozek (cherry picked from commit 2124275fe494a0241a552538c70f40c2291f3795) --- Makefile.am | 20 + src/krb5_plugin/sssd_krb5_locator_plugin.c | 16 + .../cmocka/test_sssd_krb5_locator_plugin.c | 631 ++++++++++++++++++ 3 files changed, 667 insertions(+) create mode 100644 src/tests/cmocka/test_sssd_krb5_locator_plugin.c diff --git a/Makefile.am b/Makefile.am index 9539b3cff8544cf406e3e19ab23e76e9cc8234ee..9055130ed74057987795285c243ff47584cf8316 100644 --- a/Makefile.am +++ b/Makefile.am @@ -288,6 +288,7 @@ if HAVE_CMOCKA krb5_common_test \ test_iobuf \ sss_certmap_test \ + test_sssd_krb5_locator_plugin \ $(NULL) @@ -3518,6 +3519,25 @@ sss_certmap_test_LDADD = \ libsss_certmap.la \ $(NULL) +test_sssd_krb5_locator_plugin_SOURCES = \ + src/tests/cmocka/test_sssd_krb5_locator_plugin.c \ + src/krb5_plugin/sssd_krb5_locator_plugin.c \ + $(NULL) +test_sssd_krb5_locator_plugin_CFLAGS = \ + $(AM_CFLAGS) \ + $(POPT_CFLAGS) \ + $(TALLOC_CFLAGS) \ + $(KRB5_CFLAGS) \ + -DTEST_PUBCONF_PATH=\"$(abs_builddir)/src/tests/cmocka/pubconf\" \ + $(NULL) +test_sssd_krb5_locator_plugin_LDADD = \ + $(CMOCKA_LIBS) \ + $(POPT_LIBS) \ + $(TALLOC_LIBS) \ + $(KRB5_LIBS) \ + libsss_test_common.la \ + $(NULL) + if BUILD_KCM test_kcm_json_SOURCES = \ src/tests/cmocka/test_kcm_json_marshalling.c \ diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c index 9874fd2d1ce63b69099f057dd05f6e353a12ce75..952d487c276ed51e0c3a018b0d0af59ca214525f 100644 --- a/src/krb5_plugin/sssd_krb5_locator_plugin.c +++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c @@ -38,6 +38,22 @@ #include "providers/krb5/krb5_common.h" +/* The following override of KDCINFO_TMPL and KPASSWDINFO_TMPL is not very + * elegant but since they are defined in krb5_common.h with the help of + * PUBCONF_PATH from config.h and PUBCONF_PATH can by set by a configure + * options I didn't found another way to change the path for a unit test. */ +#ifdef TEST_PUBCONF_PATH +#ifdef KDCINFO_TMPL +#undef KDCINFO_TMPL +#endif +#define KDCINFO_TMPL TEST_PUBCONF_PATH"/kdcinfo.%s" + +#ifdef KPASSWDINFO_TMPL +#undef KPASSWDINFO_TMPL +#endif +#define KPASSWDINFO_TMPL TEST_PUBCONF_PATH"/kpasswdinfo.%s" +#endif /* TEST_PUBCONF_PATH */ + #define DEFAULT_KERBEROS_PORT 88 #define DEFAULT_KADMIN_PORT 749 #define DEFAULT_KPASSWD_PORT 464 diff --git a/src/tests/cmocka/test_sssd_krb5_locator_plugin.c b/src/tests/cmocka/test_sssd_krb5_locator_plugin.c new file mode 100644 index 0000000000000000000000000000000000000000..3e7d00632ddb59da5474c0544eee6fc67edc5570 --- /dev/null +++ b/src/tests/cmocka/test_sssd_krb5_locator_plugin.c @@ -0,0 +1,631 @@ +/* + SSSD + + Unit test for SSSD's MIT Kerberos locator plugin + + Authors: + Sumit Bose + + Copyright (C) 2018 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tests/cmocka/common_mock.h" + +#define TEST_REALM "TEST.REALM" +#define TEST_IP_1 "123.231.132.213" +#define TEST_IPV6_1_PURE "7025:4d2d:2b06:e321:d971:16c0:6eeb:cc41" +#define TEST_IPV6_1 "["TEST_IPV6_1_PURE"]" +#define TEST_SERVICE_1 "22334" +#define TEST_SERVICE_2 "54321" +#define TEST_IP_1_WITH_SERVICE TEST_IP_1":"TEST_SERVICE_1 +#define TEST_IPV6_1_WITH_SERVICE TEST_IPV6_1":"TEST_SERVICE_2 + +struct test_state { + void *dummy; +}; + +static int setup(void **state) +{ + struct test_state *ts = NULL; + + assert_true(leak_check_setup()); + + ts = talloc(global_talloc_context, struct test_state); + assert_non_null(ts); + + check_leaks_push(ts); + *state = (void *)ts; + + unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM); + rmdir(TEST_PUBCONF_PATH); + + return 0; +} + +static int teardown(void **state) +{ + struct test_state *ts = talloc_get_type_abort(*state, struct test_state); + + assert_non_null(ts); + + assert_true(check_leaks_pop(ts)); + talloc_free(ts); + assert_true(leak_check_teardown()); + return 0; +} + +/* Taken from MIT Kerberos src/lib/krb5/os/locate_kdc.c and + * lib/krb5/os/os-proto.h */ + +typedef enum { + TCP_OR_UDP = 0, + TCP, + UDP, + HTTPS, +} k5_transport; + +/* A single server hostname or address. */ +struct server_entry { + char *hostname; /* NULL -> use addrlen/addr instead */ + int port; /* Used only if hostname set */ + k5_transport transport; /* May be 0 for UDP/TCP if hostname set */ + char *uri_path; /* Used only if transport is HTTPS */ + int family; /* May be 0 (aka AF_UNSPEC) if hostname set */ + int master; /* True, false, or -1 for unknown. */ + size_t addrlen; + struct sockaddr_storage addr; +}; + +/* A list of server hostnames/addresses. */ +struct serverlist { + struct server_entry *servers; + size_t nservers; +}; +#define SERVERLIST_INIT { NULL, 0 } + +/* Free up everything pointed to by the serverlist structure, but don't + * * free the structure itself. */ +void +k5_free_serverlist (struct serverlist *list) +{ + size_t i; + + for (i = 0; i < list->nservers; i++) { + free(list->servers[i].hostname); + free(list->servers[i].uri_path); + } + free(list->servers); + list->servers = NULL; + list->nservers = 0; +} + +/* Make room for a new server entry in list and return a pointer to the new + * entry. (Do not increment list->nservers.) */ +static struct server_entry * +new_server_entry(struct serverlist *list) +{ + struct server_entry *newservers, *entry; + size_t newspace = (list->nservers + 1) * sizeof(struct server_entry); + + newservers = realloc(list->servers, newspace); + if (newservers == NULL) + return NULL; + list->servers = newservers; + entry = &newservers[list->nservers]; + memset(entry, 0, sizeof(*entry)); + entry->master = -1; + return entry; +} + +/* Add an address entry to list. */ +static int +add_addr_to_list(struct serverlist *list, k5_transport transport, int family, + size_t addrlen, struct sockaddr *addr) +{ + struct server_entry *entry; + + entry = new_server_entry(list); + if (entry == NULL) + return ENOMEM; + entry->transport = transport; + entry->family = family; + entry->hostname = NULL; + entry->uri_path = NULL; + entry->addrlen = addrlen; + memcpy(&entry->addr, addr, addrlen); + list->nservers++; + return 0; +} + +struct module_callback_data { + int out_of_mem; + struct serverlist *list; +}; + +static int +module_callback(void *cbdata, int socktype, struct sockaddr *sa) +{ + struct module_callback_data *d = cbdata; + size_t addrlen; + k5_transport transport; + + if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return 0; + if (sa->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (sa->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return 0; + transport = (socktype == SOCK_STREAM) ? TCP : UDP; + if (add_addr_to_list(d->list, transport, sa->sa_family, addrlen, + sa) != 0) { + /* Assumes only error is ENOMEM. */ + d->out_of_mem = 1; + return 1; + } + return 0; +} + +krb5_error_code sssd_krb5_locator_init(krb5_context context, + void **private_data); +void sssd_krb5_locator_close(void *private_data); + +krb5_error_code sssd_krb5_locator_lookup(void *private_data, + enum locate_service_type svc, + const char *realm, + int socktype, + int family, + int (*cbfunc)(void *, int, struct sockaddr *), + void *cbdata); + +void test_init(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +void test_failed_lookup(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + struct module_callback_data cbdata = { 0 }; + + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_lookup(NULL, -1, NULL, -1, -1, NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, -1, NULL, -1, -1, NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , NULL, -1, -1, + NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, -1, + -1, NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, -1, NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, NULL, NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + NULL); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + &cbdata); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +void test_empty(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + int fd; + struct module_callback_data cbdata = { 0 }; + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + mkdir(TEST_PUBCONF_PATH, 0777); + fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT, 0777); + assert_int_not_equal(fd, -1); + close(fd); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + &cbdata); + assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE); + unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM); + rmdir(TEST_PUBCONF_PATH); + + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +void test_single(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + int fd; + struct serverlist list = SERVERLIST_INIT; + struct module_callback_data cbdata = { 0 }; + ssize_t s; + int ret; + char host[NI_MAXHOST]; + char service[NI_MAXSERV]; + + cbdata.list = &list; + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + mkdir(TEST_PUBCONF_PATH, 0777); + fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777); + assert_int_not_equal(fd, -1); + s = write(fd, TEST_IP_1, sizeof(TEST_IP_1)); + assert_int_equal(s, sizeof(TEST_IP_1)); + close(fd); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + + /* We asked for AF_INET6, but TEST_IP_1 is IPv4 */ + assert_int_equal(list.nservers, 0); + assert_null(list.servers); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + assert_int_equal(list.nservers, 1); + assert_non_null(list.servers); + assert_int_equal(list.servers[0].addrlen, 16); + ret = getnameinfo((struct sockaddr *) &list.servers[0].addr, + list.servers[0].addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST|NI_NUMERICSERV); + assert_int_equal(ret, 0); + assert_string_equal(TEST_IP_1, host); + assert_string_equal("88", service); + + k5_free_serverlist(&list); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_UNSPEC, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + assert_int_equal(list.nservers, 1); + assert_non_null(list.servers); + assert_int_equal(list.servers[0].addrlen, 16); + ret = getnameinfo((struct sockaddr *) &list.servers[0].addr, + list.servers[0].addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST|NI_NUMERICSERV); + assert_int_equal(ret, 0); + assert_string_equal(TEST_IP_1, host); + assert_string_equal("88", service); + + k5_free_serverlist(&list); + + unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM); + rmdir(TEST_PUBCONF_PATH); + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +struct test_data { + const char *ip; + bool found; +}; + +void test_multi_check_results(struct test_data *test_data, + struct serverlist *list, + const char *exp_service) +{ + int ret; + char host[NI_MAXHOST]; + char service[NI_MAXSERV]; + size_t c; + size_t d; + + /* To make sure each result from list has a matching entry in test_data we + * use a flag to mark found entries, this way we can properly detect is + * the same address is used multiple times. */ + for (d = 0; test_data[d].ip != NULL; d++) { + test_data[d].found = false; + } + + for (c = 0; c < list->nservers; c++) { + ret = getnameinfo((struct sockaddr *) &list->servers[c].addr, + list->servers[c].addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST|NI_NUMERICSERV); + assert_int_equal(ret, 0); + assert_string_equal(exp_service, service); + for (d = 0; test_data[d].ip != NULL; d++) { + /* Compare result with test_data, be aware that the test_data has + * '[]' around IPv& addresses */ + if (strncmp(host, + test_data[d].ip + (test_data[d].ip[0] == '[' ? 1 : 0), + strlen(host)) == 0 && !test_data[d].found) { + test_data[d].found = true; + break; + } + } + /* Make sure we found the result in the list */ + assert_non_null(test_data[d].ip); + } +} + +void test_multi(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + int fd; + struct serverlist list = SERVERLIST_INIT; + struct module_callback_data cbdata = { 0 }; + ssize_t s; + size_t c; + struct test_data test_data[] = { + {TEST_IP_1, false}, + {TEST_IPV6_1, false}, + {"[c89a:565b:4510:5b9f:41fe:ea81:87a0:f21b]", false}, + {"155.42.66.53", false}, + {"[f812:5941:ba69:2bae:e806:3b68:770d:d75e]", false}, + {"[3ad3:9dda:50e4:3c82:548f:eaa1:e120:6dd]", false}, + {"55.116.79.183", false}, + {"[ce8a:ee99:98cd:d8cd:218d:393e:d5a9:dc52]", false}, + /* the following address is added twice to check if + * an address can be added more than once. */ + {"37.230.88.162", false}, + {"37.230.88.162", false}, + {NULL, false} }; + + cbdata.list = &list; + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + mkdir(TEST_PUBCONF_PATH, 0777); + fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777); + assert_int_not_equal(fd, -1); + for (c = 0; test_data[c].ip != NULL; c++) { + s = write(fd, test_data[c].ip, strlen(test_data[c].ip)); + assert_int_equal(s, strlen(test_data[c].ip)); + s = write(fd, "\n", 1); + assert_int_equal(s, 1); + } + close(fd); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + + assert_int_equal(list.nservers, 5); + assert_non_null(list.servers); + test_multi_check_results(test_data, &list, "88"); + + k5_free_serverlist(&list); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + + assert_int_equal(list.nservers, 5); + assert_non_null(list.servers); + test_multi_check_results(test_data, &list, "88"); + + + k5_free_serverlist(&list); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_UNSPEC, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + + assert_int_equal(list.nservers, 10); + assert_non_null(list.servers); + test_multi_check_results(test_data, &list, "88"); + + k5_free_serverlist(&list); + + unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM); + rmdir(TEST_PUBCONF_PATH); + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +void test_service(void **state) +{ + krb5_context ctx; + krb5_error_code kerr; + void *priv; + int fd; + struct serverlist list = SERVERLIST_INIT; + struct module_callback_data cbdata = { 0 }; + ssize_t s; + int ret; + char host[NI_MAXHOST]; + char service[NI_MAXSERV]; + + cbdata.list = &list; + + kerr = krb5_init_context (&ctx); + assert_int_equal(kerr, 0); + + kerr = sssd_krb5_locator_init(ctx, &priv); + assert_int_equal(kerr, 0); + + mkdir(TEST_PUBCONF_PATH, 0777); + fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777); + assert_int_not_equal(fd, -1); + s = write(fd, TEST_IP_1_WITH_SERVICE, sizeof(TEST_IP_1_WITH_SERVICE)); + assert_int_equal(s, sizeof(TEST_IP_1_WITH_SERVICE)); + s = write(fd, "\n", 1); + assert_int_equal(s, 1); + s = write(fd, TEST_IPV6_1_WITH_SERVICE, sizeof(TEST_IPV6_1_WITH_SERVICE)); + assert_int_equal(s, sizeof(TEST_IPV6_1_WITH_SERVICE)); + close(fd); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET6, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + + assert_int_equal(list.nservers, 1); + assert_non_null(list.servers); + ret = getnameinfo((struct sockaddr *) &list.servers[0].addr, + list.servers[0].addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST|NI_NUMERICSERV); + assert_int_equal(ret, 0); + assert_string_equal(TEST_IPV6_1_PURE, host); + assert_string_equal(TEST_SERVICE_2, service); + + k5_free_serverlist(&list); + + kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, + SOCK_DGRAM, AF_INET, module_callback, + &cbdata); + assert_int_equal(kerr, 0); + assert_int_equal(list.nservers, 1); + assert_non_null(list.servers); + ret = getnameinfo((struct sockaddr *) &list.servers[0].addr, + list.servers[0].addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST|NI_NUMERICSERV); + assert_int_equal(ret, 0); + assert_string_equal(TEST_IP_1, host); + assert_string_equal(TEST_SERVICE_1, service); + + k5_free_serverlist(&list); + + + unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM); + rmdir(TEST_PUBCONF_PATH); + sssd_krb5_locator_close(priv); + + krb5_free_context(ctx); +} + +int main(int argc, const char *argv[]) +{ + poptContext pc; + int opt; + int ret; + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_DEBUG_OPTS + POPT_TABLEEND + }; + + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_init, + setup, teardown), + cmocka_unit_test_setup_teardown(test_failed_lookup, + setup, teardown), + cmocka_unit_test_setup_teardown(test_empty, + setup, teardown), + cmocka_unit_test_setup_teardown(test_single, + setup, teardown), + cmocka_unit_test_setup_teardown(test_multi, + setup, teardown), + cmocka_unit_test_setup_teardown(test_service, + setup, teardown), + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + poptFreeContext(pc); + + DEBUG_CLI_INIT(debug_level); + + ret = cmocka_run_group_tests(tests, NULL, NULL); + + return ret; +} -- 2.17.1