LCOV - code coverage report
Current view: top level - tests/cmocka - test_resolv_fake.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 161 164 98.2 %
Date: 2015-10-19 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jakub Hrozek <jhrozek@redhat.com>
       4             : 
       5             :     Copyright (C) 2014 Red Hat
       6             : 
       7             :     SSSD tests: Resolver tests using a fake resolver library
       8             : 
       9             :     This program is free software; you can redistribute it and/or modify
      10             :     it under the terms of the GNU General Public License as published by
      11             :     the Free Software Foundation; either version 3 of the License, or
      12             :     (at your option) any later version.
      13             : 
      14             :     This program is distributed in the hope that it will be useful,
      15             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :     GNU General Public License for more details.
      18             : 
      19             :     You should have received a copy of the GNU General Public License
      20             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include <talloc.h>
      24             : #include <tevent.h>
      25             : #include <errno.h>
      26             : #include <popt.h>
      27             : #include <arpa/inet.h>
      28             : #include <netinet/in.h>
      29             : #include <sys/types.h>
      30             : #include <stdarg.h>
      31             : #include <stdlib.h>
      32             : 
      33             : #include <resolv.h>
      34             : 
      35             : #include "tests/cmocka/common_mock.h"
      36             : #include "tests/cmocka/common_mock_resp.h"
      37             : 
      38             : #define TEST_BUFSIZE         1024
      39             : #define TEST_DEFAULT_TIMEOUT 5
      40             : #define TEST_SRV_QUERY "_ldap._tcp.sssd.com"
      41             : 
      42             : static TALLOC_CTX *global_mock_context = NULL;
      43             : 
      44             : struct srv_rrdata {
      45             :     uint16_t port;
      46             :     uint16_t prio;
      47             :     uint16_t weight;
      48             :     uint32_t ttl;
      49             :     const char *hostname;
      50             : };
      51             : 
      52           1 : static ssize_t dns_header(unsigned char **buf, size_t ancount)
      53             : {
      54             :     uint8_t *hb;
      55             :     HEADER h;
      56             : 
      57           1 :     hb = *buf;
      58           1 :     memset(hb, 0, NS_HFIXEDSZ);
      59           1 :     memset(&h, 0, sizeof(h));
      60             : 
      61           1 :     h.id = res_randomid();     /* random query ID */
      62           1 :     h.qr = 1;                  /* response flag */
      63           1 :     h.rd = 1;                  /* recursion desired */
      64           1 :     h.ra = 1;                  /* resursion available */
      65             : 
      66           1 :     h.qdcount = htons(1);          /* no. of questions */
      67           1 :     h.ancount = htons(ancount);    /* no. of answers */
      68           1 :     h.arcount = htons(0);          /* no. of add'tl records */
      69           1 :     memcpy(hb, &h, sizeof(h));
      70             : 
      71           1 :     hb += NS_HFIXEDSZ;              /* move past the header */
      72           1 :     *buf = hb;
      73             : 
      74           1 :     return NS_HFIXEDSZ;
      75             : }
      76             : 
      77           1 : static ssize_t dns_question(const char *question,
      78             :                             uint16_t type,
      79             :                             uint8_t **question_ptr,
      80             :                             size_t remaining)
      81             : {
      82           1 :     unsigned char *qb = *question_ptr;
      83             :     int n;
      84             : 
      85           1 :     n = ns_name_compress(question, qb, remaining, NULL, NULL);
      86           1 :     assert_true(n > 0);
      87             : 
      88           1 :     qb += n;
      89           1 :     remaining -= n;
      90             : 
      91           1 :     NS_PUT16(type, qb);
      92           1 :     NS_PUT16(ns_c_in, qb);
      93             : 
      94           1 :     *question_ptr = qb;
      95           1 :     return n + 2 * sizeof(uint16_t);
      96             : }
      97             : 
      98           2 : static ssize_t add_rr_common(uint16_t type,
      99             :                              uint32_t ttl,
     100             :                              size_t rdata_size,
     101             :                              const char *key,
     102             :                              size_t remaining,
     103             :                              uint8_t **rdata_ptr)
     104             : {
     105           2 :     uint8_t *rd = *rdata_ptr;
     106           2 :     ssize_t written = 0;
     107             : 
     108           2 :     written = ns_name_compress(key, rd, remaining, NULL, NULL);
     109           2 :     assert_int_not_equal(written, -1);
     110           2 :     rd += written;
     111           2 :     remaining -= written;
     112             : 
     113           2 :     assert_true(remaining > 3 * sizeof(uint16_t) + sizeof(uint32_t));
     114           2 :     NS_PUT16(type, rd);
     115           2 :     NS_PUT16(ns_c_in, rd);
     116           2 :     NS_PUT32(ttl, rd);
     117           2 :     NS_PUT16(rdata_size, rd);
     118             : 
     119           2 :     assert_true(remaining > rdata_size);
     120           2 :     *rdata_ptr = rd;
     121           2 :     return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size;
     122             : }
     123             : 
     124           2 : static ssize_t add_srv_rr(struct srv_rrdata *rr,
     125             :                           const char *question,
     126             :                           uint8_t *answer,
     127             :                           size_t anslen)
     128             : {
     129           2 :     uint8_t *a = answer;
     130             :     ssize_t resp_size;
     131             :     size_t rdata_size;
     132             :     unsigned char hostname_compressed[MAXDNAME];
     133             :     ssize_t compressed_len;
     134             : 
     135           2 :     rdata_size = 3 * sizeof(uint16_t);
     136             : 
     137             :     /* Prepare the data to write */
     138           2 :     compressed_len = ns_name_compress(rr->hostname,
     139             :                                       hostname_compressed, MAXDNAME,
     140             :                                       NULL, NULL);
     141           2 :     assert_int_not_equal(compressed_len, -1);
     142           2 :     rdata_size += compressed_len;
     143             : 
     144           2 :     resp_size = add_rr_common(ns_t_srv, rr->ttl, rdata_size,
     145             :                               question, anslen, &a);
     146             : 
     147           2 :     NS_PUT16(rr->prio, a);
     148           2 :     NS_PUT16(rr->weight, a);
     149           2 :     NS_PUT16(rr->port, a);
     150           2 :     memcpy(a, hostname_compressed, compressed_len);
     151             : 
     152           2 :     return resp_size;
     153             : }
     154             : 
     155           1 : unsigned char *create_srv_buffer(TALLOC_CTX *mem_ctx,
     156             :                                  const char *question,
     157             :                                  struct srv_rrdata *rrs,
     158             :                                  size_t n_rrs,
     159             :                                  size_t *_buflen)
     160             : {
     161             :     unsigned char *buf;
     162             :     unsigned char *buf_head;
     163             :     ssize_t len;
     164             :     ssize_t i;
     165           1 :     ssize_t total = 0;
     166             : 
     167           1 :     buf = talloc_zero_array(mem_ctx, unsigned char, TEST_BUFSIZE);
     168           1 :     assert_non_null(buf);
     169           1 :     buf_head = buf;
     170             : 
     171           1 :     len = dns_header(&buf, n_rrs);
     172           1 :     assert_true(len > 0);
     173           1 :     total += len;
     174             : 
     175           1 :     len = dns_question(question, ns_t_srv, &buf, TEST_BUFSIZE - total);
     176           1 :     assert_true(len > 0);
     177           1 :     total += len;
     178             : 
     179             :     /* answer */
     180           3 :     for (i = 0; i < n_rrs; i++) {
     181           2 :         len = add_srv_rr(&rrs[i], question, buf, TEST_BUFSIZE - total);
     182           2 :         assert_true(len > 0);
     183           2 :         total += len;
     184           2 :         buf += len;
     185             :     }
     186             : 
     187           1 :     *_buflen = total;
     188           1 :     return buf_head;
     189             : }
     190             : 
     191             : struct fake_ares_query {
     192             :     int status;
     193             :     int timeouts;
     194             :     unsigned char *abuf;
     195             :     int alen;
     196             : };
     197             : 
     198           1 : void mock_ares_query(int status, int timeouts, unsigned char *abuf, int alen)
     199             : {
     200           1 :     will_return(__wrap_ares_query, status);
     201           1 :     will_return(__wrap_ares_query, timeouts);
     202           1 :     will_return(__wrap_ares_query, abuf);
     203           1 :     will_return(__wrap_ares_query, alen);
     204           1 : }
     205             : 
     206           1 : void __wrap_ares_query(ares_channel channel, const char *name, int dnsclass,
     207             :                        int type, ares_callback callback, void *arg)
     208             : {
     209             :     struct fake_ares_query query;
     210             : 
     211           1 :     query.status = sss_mock_type(int);
     212           1 :     query.timeouts = sss_mock_type(int);
     213           1 :     query.abuf = sss_mock_ptr_type(unsigned char *);
     214           1 :     query.alen = sss_mock_type(int);
     215             : 
     216           1 :     callback(arg, query.status, query.timeouts, query.abuf, query.alen);
     217           1 : }
     218             : 
     219             : /* The unit test */
     220             : struct resolv_fake_ctx {
     221             :     struct resolv_ctx *resolv;
     222             :     struct sss_test_ctx *ctx;
     223             : };
     224             : 
     225           1 : static int test_resolv_fake_setup(void **state)
     226             : {
     227             :     struct resolv_fake_ctx *test_ctx;
     228             :     int ret;
     229             : 
     230           1 :     assert_true(leak_check_setup());
     231           1 :     global_mock_context = talloc_new(global_talloc_context);
     232           1 :     assert_non_null(global_mock_context);
     233             : 
     234           1 :     test_ctx = talloc_zero(global_mock_context,
     235             :                            struct resolv_fake_ctx);
     236           1 :     assert_non_null(test_ctx);
     237             : 
     238           1 :     test_ctx->ctx = create_ev_test_ctx(test_ctx);
     239           1 :     assert_non_null(test_ctx->ctx);
     240             : 
     241           1 :     ret = resolv_init(test_ctx, test_ctx->ctx->ev,
     242             :                       TEST_DEFAULT_TIMEOUT, &test_ctx->resolv);
     243           1 :     assert_int_equal(ret, EOK);
     244             : 
     245           1 :     *state = test_ctx;
     246           1 :     return 0;
     247             : }
     248             : 
     249           1 : static int test_resolv_fake_teardown(void **state)
     250             : {
     251           1 :     struct resolv_fake_ctx *test_ctx =
     252           1 :         talloc_get_type(*state, struct resolv_fake_ctx);
     253             : 
     254           1 :     talloc_free(test_ctx);
     255           1 :     talloc_free(global_mock_context);
     256           1 :     assert_true(leak_check_teardown());
     257           1 :     return 0;
     258             : }
     259             : 
     260           1 : void test_resolv_fake_srv_done(struct tevent_req *req)
     261             : {
     262             :     errno_t ret;
     263             :     TALLOC_CTX *tmp_ctx;
     264             :     int status;
     265             :     uint32_t ttl;
     266           1 :     struct ares_srv_reply *srv_replies = NULL;
     267           1 :     struct resolv_fake_ctx *test_ctx =
     268           1 :         tevent_req_callback_data(req, struct resolv_fake_ctx);
     269             : 
     270           1 :     tmp_ctx = talloc_new(test_ctx);
     271           1 :     assert_non_null(tmp_ctx);
     272             : 
     273           1 :     ret = resolv_getsrv_recv(tmp_ctx, req, &status, NULL,
     274             :                              &srv_replies, &ttl);
     275           1 :     assert_int_equal(ret, EOK);
     276             : 
     277           1 :     assert_non_null(srv_replies);
     278           1 :     assert_int_equal(srv_replies->priority, 1);
     279           1 :     assert_int_equal(srv_replies->weight, 40);
     280           1 :     assert_int_equal(srv_replies->port, 389);
     281           1 :     assert_string_equal(srv_replies->host, "ldap.sssd.com");
     282             : 
     283           1 :     srv_replies = srv_replies->next;
     284           1 :     assert_non_null(srv_replies);
     285           1 :     assert_int_equal(srv_replies->priority, 1);
     286           1 :     assert_int_equal(srv_replies->weight, 60);
     287           1 :     assert_int_equal(srv_replies->port, 389);
     288           1 :     assert_string_equal(srv_replies->host, "ldap2.sssd.com");
     289             : 
     290           1 :     srv_replies = srv_replies->next;
     291           1 :     assert_null(srv_replies);
     292             : 
     293           1 :     assert_int_equal(ttl, 500);
     294             : 
     295           1 :     talloc_free(tmp_ctx);
     296           1 :     test_ev_done(test_ctx->ctx, EOK);
     297           1 : }
     298             : 
     299           1 : void test_resolv_fake_srv(void **state)
     300             : {
     301             :     int ret;
     302             :     struct tevent_req *req;
     303           1 :     struct resolv_fake_ctx *test_ctx =
     304           1 :         talloc_get_type(*state, struct resolv_fake_ctx);
     305             : 
     306             :     unsigned char *buf;
     307             :     size_t buflen;
     308             : 
     309             :     struct srv_rrdata rr[2];
     310             : 
     311           1 :     rr[0].prio = 1;
     312           1 :     rr[0].port = 389;
     313           1 :     rr[0].weight = 40;
     314           1 :     rr[0].ttl = 600;
     315           1 :     rr[0].hostname = "ldap.sssd.com";
     316             : 
     317           1 :     rr[1].prio = 1;
     318           1 :     rr[1].port = 389;
     319           1 :     rr[1].weight = 60;
     320           1 :     rr[1].ttl = 500;
     321           1 :     rr[1].hostname = "ldap2.sssd.com";
     322             : 
     323           1 :     buf = create_srv_buffer(test_ctx, TEST_SRV_QUERY, rr, 2, &buflen);
     324           1 :     assert_non_null(buf);
     325           1 :     mock_ares_query(0, 0, buf, buflen);
     326             : 
     327           1 :     req = resolv_getsrv_send(test_ctx, test_ctx->ctx->ev,
     328             :                              test_ctx->resolv, TEST_SRV_QUERY);
     329           1 :     assert_non_null(req);
     330           1 :     tevent_req_set_callback(req, test_resolv_fake_srv_done, test_ctx);
     331             : 
     332           1 :     ret = test_ev_loop(test_ctx->ctx);
     333           1 :     assert_int_equal(ret, ERR_OK);
     334           1 : }
     335             : 
     336           1 : int main(int argc, const char *argv[])
     337             : {
     338             :     int rv;
     339             :     poptContext pc;
     340             :     int opt;
     341           6 :     struct poptOption long_options[] = {
     342             :         POPT_AUTOHELP
     343           5 :         SSSD_DEBUG_OPTS
     344             :         POPT_TABLEEND
     345             :     };
     346             : 
     347           1 :     const struct CMUnitTest tests[] = {
     348             :         cmocka_unit_test_setup_teardown(test_resolv_fake_srv,
     349             :                                         test_resolv_fake_setup,
     350             :                                         test_resolv_fake_teardown),
     351             :     };
     352             : 
     353             :     /* Set debug level to invalid value so we can deside if -d 0 was used. */
     354           1 :     debug_level = SSSDBG_INVALID;
     355             : 
     356           1 :     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
     357           1 :     while((opt = poptGetNextOpt(pc)) != -1) {
     358             :         switch(opt) {
     359             :         default:
     360           0 :             fprintf(stderr, "\nInvalid option %s: %s\n\n",
     361             :                     poptBadOption(pc, 0), poptStrerror(opt));
     362           0 :             poptPrintUsage(pc, stderr, 0);
     363           0 :             return 1;
     364             :         }
     365             :     }
     366           1 :     poptFreeContext(pc);
     367             : 
     368           1 :     DEBUG_CLI_INIT(debug_level);
     369             : 
     370             :     /* Even though normally the tests should clean up after themselves
     371             :      * they might not after a failed run. Remove the old db to be sure */
     372           1 :     tests_set_cwd();
     373             : 
     374           1 :     rv = cmocka_run_group_tests(tests, NULL, NULL);
     375           1 :     return rv;
     376             : }

Generated by: LCOV version 1.10