test_dyndns.c revision b0a8ed519554f8896e35812e0759862c33f157fe
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/*
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen Authors:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen Jakub Hrozek <jhrozek@redhat.com>
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen Copyright (C) 2013 Red Hat
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen SSSD tests: Dynamic DNS tests
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen This program is free software; you can redistribute it and/or modify
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen it under the terms of the GNU General Public License as published by
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen the Free Software Foundation; either version 3 of the License, or
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (at your option) any later version.
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen This program is distributed in the hope that it will be useful,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen GNU General Public License for more details.
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen You should have received a copy of the GNU General Public License
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen*/
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include <talloc.h>
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen#include <tevent.h>
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen#include <errno.h>
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen#include <popt.h>
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen#include <unistd.h>
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen#include <sys/types.h>
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen#include <ifaddrs.h>
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include <arpa/inet.h>
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen/* In order to access opaque types */
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen#include "providers/dp_dyndns.c"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "tests/cmocka/common_mock.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "tests/cmocka/common_mock_be.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "src/providers/dp_dyndns.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#define TESTS_PATH "tests_dyndns"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#define TEST_CONF_DB "test_dyndns_conf.ldb"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#define TEST_DOM_NAME "dyndns_test"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#define TEST_ID_PROVIDER "ldap"
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenenum mock_nsupdate_states {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen MOCK_NSUPDATE_OK,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen MOCK_NSUPDATE_ERR,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen MOCK_NSUPDATE_TIMEOUT,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen};
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic TALLOC_CTX *global_mock_context = NULL;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstruct dyndns_test_ctx {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct sss_test_ctx *tctx;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct be_ctx *be_ctx;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct be_nsupdate_ctx *update_ctx;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen enum mock_nsupdate_states state;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen int child_status;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen int child_retval;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen};
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic struct dyndns_test_ctx *dyndns_test_ctx;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenvoid __wrap_execv(const char *path, char *const argv[])
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen int err;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen switch (dyndns_test_ctx->state) {
97ee61d723f99fa20fc9c95cfe17b3816c613ff5Timo Sirainen case MOCK_NSUPDATE_OK:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen DEBUG(SSSDBG_FUNC_DATA, "nsupdate success test case\n");
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen err = 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen break;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen case MOCK_NSUPDATE_ERR:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen DEBUG(SSSDBG_FUNC_DATA, "nsupdate error test case\n");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen err = 1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen break;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen case MOCK_NSUPDATE_TIMEOUT:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen DEBUG(SSSDBG_FUNC_DATA, "nsupdate timeout test case\n");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen err = 2;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen sleep(3);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen break;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen default:
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "unknown test case\n");
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen err = 255;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen break;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
75f3dddc3a5922c92a1bdb921b653ead51227cabTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS, "Child exiting with status %d\n", err);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen _exit(err);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenint __wrap_getifaddrs(struct ifaddrs **_ifap)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen struct ifaddrs *ifap = NULL;
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen struct ifaddrs *ifap_prev = NULL;
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen struct ifaddrs *ifap_head = NULL;
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen char *name;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen char *straddr;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen int ad_family;
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen struct sockaddr_in *sa;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen void *dst;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen while ((name = sss_mock_ptr_type(char *)) != NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen straddr = sss_mock_ptr_type(char *);
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen if (straddr == NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen errno = EINVAL;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen goto fail;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ad_family = sss_mock_type(int);
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen ifap = talloc_zero(global_mock_context, struct ifaddrs);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (ifap == NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen errno = ENOMEM; /* getifaddrs sets errno, too */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen goto fail;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen if (ifap_prev) {
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen ifap_prev->ifa_next = ifap;
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen } else {
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen ifap_head = ifap;
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen }
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen ifap_prev = ifap;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen ifap->ifa_name = talloc_strdup(ifap, name);
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen if (ifap->ifa_name == NULL) {
a4d796994ba01c207f1d3e373f58f06c6779af53Timo Sirainen errno = ENOMEM;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen goto fail;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* Do not alocate directly on ifap->ifa_addr to
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen * avoid alignment warnings */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (ad_family == AF_INET) {
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen sa = talloc(ifap, struct sockaddr_in);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } else if (ad_family == AF_INET6) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen sa = (struct sockaddr_in *) talloc(ifap, struct sockaddr_in6);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } else {
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen errno = EINVAL;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen goto fail;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen }
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (sa == NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen errno = ENOMEM;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen goto fail;
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen sa->sin_family = ad_family;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (ad_family == AF_INET) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dst = &sa->sin_addr;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } else if (ad_family == AF_INET6) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen dst = &((struct sockaddr_in6 *)sa)->sin6_addr;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen } else {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen errno = EINVAL;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen goto fail;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen /* convert straddr into ifa_addr */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (inet_pton(ad_family, straddr, dst) != 1) {
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen goto fail;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen ifap->ifa_addr = (struct sockaddr *) sa;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen }
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen *_ifap = ifap_head;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen return 0;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenfail:
talloc_free(ifap);
return -1;
}
void __wrap_freeifaddrs(struct ifaddrs *ifap)
{
talloc_free(ifap);
}
static void dyndns_test_done(struct tevent_req *req)
{
struct dyndns_test_ctx *ctx =
tevent_req_callback_data(req, struct dyndns_test_ctx);
ctx->child_retval = -1;
ctx->tctx->error = be_nsupdate_recv(req, &ctx->child_status);
talloc_zfree(req);
ctx->tctx->done = true;
}
void will_return_getifaddrs(const char *ifname, const char *straddr,
int af_family)
{
will_return(__wrap_getifaddrs, ifname);
if (ifname) {
will_return(__wrap_getifaddrs, straddr);
}
if (straddr) {
will_return(__wrap_getifaddrs, af_family);
}
}
void dyndns_test_get_ifaddr(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist;
char straddr[128];
check_leaks_push(dyndns_test_ctx);
will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
assert_int_equal(ret, EOK);
/* There must be only one address with the correct value */
assert_non_null(addrlist);
assert_non_null(addrlist->addr);
assert_null(addrlist->next);
assert_null(addrlist->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) addrlist->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
assert_string_equal(straddr, "192.168.0.1");
talloc_free(addrlist);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_get_multi_ifaddr(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist;
struct sss_iface_addr *sss_if_addr;
char straddr[128];
check_leaks_push(dyndns_test_ctx);
will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
assert_int_equal(ret, EOK);
sss_if_addr = addrlist;
assert_non_null(sss_if_addr);
assert_non_null(sss_if_addr->addr);
assert_non_null(sss_if_addr->next);
assert_null(sss_if_addr->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) sss_if_addr->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "192.168.0.1");
sss_if_addr = addrlist->next;
assert_non_null(sss_if_addr);
assert_non_null(sss_if_addr->addr);
assert_null(sss_if_addr->next);
assert_non_null(sss_if_addr->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) sss_if_addr->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "192.168.0.2");
talloc_free(addrlist);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_get_ifaddr_enoent(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist = NULL;
check_leaks_push(dyndns_test_ctx);
will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
&addrlist);
assert_int_equal(ret, ENOENT);
talloc_free(addrlist);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_dualstack(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist;
struct sss_iface_addr *sss_if_addrs;
char straddr[128];
int i;
check_leaks_push(dyndns_test_ctx);
/* getifaddrs is called twice in sss_get_dualstack_addresses() */
for (i = 0; i < 2; i++) {
will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
}
struct sockaddr_in sin;
memset (&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
ret = sss_get_dualstack_addresses(dyndns_test_ctx,
(struct sockaddr *) &sin,
&addrlist);
assert_int_equal(ret, EOK);
sss_if_addrs = addrlist;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_non_null(sss_if_addrs->next);
assert_null(sss_if_addrs->prev);
assert_non_null(inet_ntop(AF_INET6,
&((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
straddr, INET6_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "2001:cdba::555");
sss_if_addrs = addrlist->next;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_null(sss_if_addrs->next);
assert_non_null(sss_if_addrs->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "192.168.0.2");
talloc_free(addrlist);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_dualstack_multiple_addresses(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist;
struct sss_iface_addr *sss_if_addrs;
char straddr[128];
int i;
check_leaks_push(dyndns_test_ctx);
/* getifaddrs is called twice in sss_get_dualstack_addresses() */
for (i = 0; i < 2; i++) {
will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
/* loopback - invalid for dns (should be skipped) */
will_return_getifaddrs("eth0", "::1", AF_INET6);
/* linklocal - invalid for dns (should be skipped) */
will_return_getifaddrs("eth0", "fe80::5054:ff:fe4a:65ae", AF_INET6);
will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
}
struct sockaddr_in sin;
memset (&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
ret = sss_get_dualstack_addresses(dyndns_test_ctx,
(struct sockaddr *) &sin,
&addrlist);
assert_int_equal(ret, EOK);
sss_if_addrs = addrlist;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_non_null(sss_if_addrs->next);
assert_null(sss_if_addrs->prev);
assert_non_null(inet_ntop(AF_INET6,
&((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
straddr, INET6_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "2001:cdba::444");
sss_if_addrs = sss_if_addrs->next;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_non_null(sss_if_addrs->prev);
assert_non_null(sss_if_addrs->next);
assert_non_null(inet_ntop(AF_INET6,
&((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
straddr, INET6_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "2001:cdba::555");
sss_if_addrs = sss_if_addrs->next;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_non_null(sss_if_addrs->next);
assert_non_null(sss_if_addrs->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "192.168.0.1");
sss_if_addrs = sss_if_addrs->next;
assert_non_null(sss_if_addrs);
assert_non_null(sss_if_addrs->addr);
assert_null(sss_if_addrs->next);
assert_non_null(sss_if_addrs->prev);
assert_non_null(inet_ntop(AF_INET,
&((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
straddr, INET_ADDRSTRLEN));
/* ip addresses are returned in different order */
assert_string_equal(straddr, "192.168.0.2");
talloc_free(addrlist);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_dualstack_no_iface(void **state)
{
errno_t ret;
struct sss_iface_addr *addrlist;
check_leaks_push(dyndns_test_ctx);
will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
struct sockaddr_in sin;
memset (&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr ("192.168.0.3");
ret = sss_get_dualstack_addresses(dyndns_test_ctx,
(struct sockaddr *) &sin,
&addrlist);
assert_int_equal(ret, ENOENT);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
void dyndns_test_ok(void **state)
{
struct tevent_req *req;
errno_t ret;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(global_talloc_context);
assert_non_null(tmp_ctx);
check_leaks_push(tmp_ctx);
dyndns_test_ctx->state = MOCK_NSUPDATE_OK;
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
discard_const("test message"), false);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
/* Wait until the test finishes with EOK */
ret = test_ev_loop(dyndns_test_ctx->tctx);
DEBUG(SSSDBG_TRACE_LIBS,
"Child request returned [%d]: %s\n", ret, strerror(ret));
assert_int_equal(ret, EOK);
assert_true(WIFEXITED(dyndns_test_ctx->child_status));
assert_int_equal(WEXITSTATUS(dyndns_test_ctx->child_status), 0);
assert_true(check_leaks_pop(tmp_ctx) == true);
talloc_free(tmp_ctx);
}
void dyndns_test_error(void **state)
{
struct tevent_req *req;
errno_t ret;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(global_talloc_context);
assert_non_null(tmp_ctx);
check_leaks_push(tmp_ctx);
dyndns_test_ctx->state = MOCK_NSUPDATE_ERR;
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
discard_const("test message"), false);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
/* Wait until the test finishes with EIO (child error) */
ret = test_ev_loop(dyndns_test_ctx->tctx);
DEBUG(SSSDBG_TRACE_LIBS,
"Child request returned [%d]: %s\n", ret, strerror(ret));
assert_int_equal(ret, ERR_DYNDNS_FAILED);
assert_true(WIFEXITED(dyndns_test_ctx->child_status));
assert_int_equal(WEXITSTATUS(dyndns_test_ctx->child_status), 1);
assert_true(check_leaks_pop(tmp_ctx) == true);
talloc_free(tmp_ctx);
}
void dyndns_test_timeout(void **state)
{
struct tevent_req *req;
errno_t ret;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(global_talloc_context);
assert_non_null(tmp_ctx);
check_leaks_push(tmp_ctx);
dyndns_test_ctx->state = MOCK_NSUPDATE_TIMEOUT;
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
discard_const("test message"), false);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
/* Wait until the test finishes with EIO (child error) */
ret = test_ev_loop(dyndns_test_ctx->tctx);
/* The event queue may not be empty. We need to make sure that all events
* are processed. Unfortunately, tevent_loop_wait() contains a bug that
* prevents exiting the loop even if there are no remaining events, thus
* we have to use tevent_loop_once().
*
* FIXME: use tevent_loop_wait() when the bug is fixed
* https://bugzilla.samba.org/show_bug.cgi?id=10012
*/
tevent_loop_once(dyndns_test_ctx->tctx->ev); /* SIGCHLD handler */
tevent_loop_once(dyndns_test_ctx->tctx->ev); /* nsupdate_child_handler */
DEBUG(SSSDBG_TRACE_LIBS,
"Child request returned [%d]: %s\n", ret, strerror(ret));
assert_int_equal(ret, ERR_DYNDNS_TIMEOUT);
assert_true(check_leaks_pop(tmp_ctx) == true);
talloc_free(tmp_ctx);
}
void dyndns_test_timer(void *pvt)
{
struct dyndns_test_ctx *ctx = talloc_get_type(pvt, struct dyndns_test_ctx);
static int ncalls = 0;
ncalls++;
if (ncalls == 1) {
be_nsupdate_timer_schedule(ctx->tctx->ev, ctx->update_ctx);
} else if (ncalls == 2) {
ctx->tctx->done = true;
}
ctx->tctx->error = ERR_OK;
}
void dyndns_test_interval(void **state)
{
errno_t ret;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(global_talloc_context);
assert_non_null(tmp_ctx);
check_leaks_push(tmp_ctx);
ret = be_nsupdate_init(tmp_ctx, dyndns_test_ctx->be_ctx, NULL,
&dyndns_test_ctx->update_ctx);
assert_int_equal(ret, EOK);
ret = be_nsupdate_init_timer(dyndns_test_ctx->update_ctx,
dyndns_test_ctx->be_ctx->ev,
dyndns_test_timer, dyndns_test_ctx);
assert_int_equal(ret, EOK);
/* Wait until the timer hits */
ret = test_ev_loop(dyndns_test_ctx->tctx);
DEBUG(SSSDBG_TRACE_LIBS,
"Child request returned [%d]: %s\n", ret, strerror(ret));
assert_int_equal(ret, ERR_OK);
talloc_free(dyndns_test_ctx->update_ctx);
assert_true(check_leaks_pop(tmp_ctx) == true);
talloc_free(tmp_ctx);
}
/* Testsuite setup and teardown */
static int dyndns_test_setup(void **state)
{
struct sss_test_conf_param params[] = {
{ "dyndns_update", "true" },
{ "dyndns_refresh_interval", "2" },
{ NULL, NULL }, /* Sentinel */
};
assert_true(leak_check_setup());
global_mock_context = talloc_new(global_talloc_context);
assert_non_null(global_mock_context);
dyndns_test_ctx = talloc_zero(global_talloc_context, struct dyndns_test_ctx);
assert_non_null(dyndns_test_ctx);
dyndns_test_ctx->tctx = create_dom_test_ctx(dyndns_test_ctx, TESTS_PATH,
TEST_CONF_DB, TEST_DOM_NAME,
TEST_ID_PROVIDER, params);
assert_non_null(dyndns_test_ctx->tctx);
dyndns_test_ctx->be_ctx = mock_be_ctx(dyndns_test_ctx, dyndns_test_ctx->tctx);
assert_non_null(dyndns_test_ctx->be_ctx);
return 0;
}
static int dyndns_test_simple_setup(void **state)
{
assert_true(leak_check_setup());
global_mock_context = talloc_new(global_talloc_context);
assert_non_null(global_mock_context);
dyndns_test_ctx = talloc_zero(global_talloc_context, struct dyndns_test_ctx);
assert_non_null(dyndns_test_ctx);
return 0;
}
static int dyndns_test_teardown(void **state)
{
talloc_free(dyndns_test_ctx);
talloc_free(global_mock_context);
assert_true(leak_check_teardown());
return 0;
}
int main(int argc, const char *argv[])
{
int rv;
int no_cleanup = 0;
poptContext pc;
int opt;
struct poptOption long_options[] = {
POPT_AUTOHELP
SSSD_DEBUG_OPTS
{"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
_("Do not delete the test database after a test run"), NULL },
POPT_TABLEEND
};
const struct CMUnitTest tests[] = {
/* Utility functions unit test */
cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr,
dyndns_test_simple_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_get_multi_ifaddr,
dyndns_test_simple_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent,
dyndns_test_simple_setup,
dyndns_test_teardown),
/* Dynamic DNS update unit tests*/
cmocka_unit_test_setup_teardown(dyndns_test_ok,
dyndns_test_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_error,
dyndns_test_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_timeout,
dyndns_test_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_interval,
dyndns_test_setup,
dyndns_test_teardown),
/* Dynamic DNS dualstack unit tests*/
cmocka_unit_test_setup_teardown(dyndns_test_dualstack,
dyndns_test_simple_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_dualstack_multiple_addresses,
dyndns_test_simple_setup,
dyndns_test_teardown),
cmocka_unit_test_setup_teardown(dyndns_test_dualstack_no_iface,
dyndns_test_simple_setup,
dyndns_test_teardown),
};
/* Set debug level to invalid value so we can deside 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);
/* Even though normally the tests should clean up after themselves
* they might not after a failed run. Remove the old db to be sure */
tests_set_cwd();
test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
test_dom_suite_setup(TESTS_PATH);
rv = cmocka_run_group_tests(tests, NULL, NULL);
if (rv == 0 && !no_cleanup) {
test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
}
return rv;
}