From 09631e038be255ad81992d141844cf76ba1e6533 Mon Sep 17 00:00:00 2001 From: "Craig E. Despeaux" Date: Wed, 18 Dec 2013 16:23:07 -0500 Subject: [PATCH] New source file for getdns_general and updates to getdns_general_sync. --- src/test/Makefile.in | 5 +- src/test/check_getdns_general.c | 717 +++++++++++++++++++++++++++ src/test/check_getdns_general_sync.c | 5 +- 3 files changed, 722 insertions(+), 5 deletions(-) create mode 100644 src/test/check_getdns_general.c diff --git a/src/test/Makefile.in b/src/test/Makefile.in index a993923b..2722dde0 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -19,7 +19,7 @@ CC=gcc CFLAGS=@CFLAGS@ -Wall -I$(srcdir)/ -I$(srcdir)/../ -I/usr/local/include -std=c99 $(cflags) LDFLAGS=@LDFLAGS@ -L. -L.. -L/usr/local/lib LDLIBS=-lgetdns @LIBS@ -lcheck -PROGRAMS=tests_dict tests_list tests_stub_async tests_stub_sync check_getdns_general_sync check_getdns_address_sync +PROGRAMS=tests_dict tests_list tests_stub_async tests_stub_sync check_getdns_general check_getdns_general_sync check_getdns_address_sync .SUFFIXES: .c .o .a .lo .h @@ -42,6 +42,9 @@ tests_stub_async: tests_stub_async.o testmessages.o tests_stub_sync: tests_stub_sync.o $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ tests_stub_sync.o +check_getdns_general: check_getdns_general.o + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns_general.o + check_getdns_general_sync: check_getdns_general_sync.o $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns_general_sync.o diff --git a/src/test/check_getdns_general.c b/src/test/check_getdns_general.c new file mode 100644 index 00000000..5f05a92a --- /dev/null +++ b/src/test/check_getdns_general.c @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 +#define MAXLEN 200 + +struct extracted_response { + uint32_t top_answer_type; + struct getdns_bindata *top_canonical_name; + struct getdns_list *just_address_answers; + struct getdns_list *replies_full; + struct getdns_list *replies_tree; + struct getdns_dict *replies_tree_sub_dict; + struct getdns_list *additional; + struct getdns_list *answer; + uint32_t answer_type; + struct getdns_list *authority; + struct getdns_bindata *canonical_name; + struct getdns_dict *header; + struct getdns_dict *question; + uint32_t status; +}; + +/* + * The STANDARD_TEST_DECLARATIONS macro defines + * ithe standard variable definitions most tests + * will need. + * + */ +#define STANDARD_TEST_DECLARATIONS \ + struct getdns_context *context = NULL; \ + struct getdns_dict *response = NULL; \ + struct event_base *event_base; \ + getdns_transaction_t transaction_id = 0; \ + size_t buflen = MAXLEN; \ + char error_string[MAXLEN]; + +/* + * The ASSERT_RC macro is used to assert + * whether the return code from the last + * getdns API call is what was expected. + */ +#define ASSERT_RC(rc, expected_rc, prefix) \ + getdns_strerror(rc, error_string, buflen); \ + ck_assert_msg(rc == expected_rc, \ + "%s: expecting %s: %d, but received: %d: %s", \ + prefix, #expected_rc, expected_rc, rc, error_string); + +/* + * The CONTEXT_CREATE macro is used to + * create a context and assert the proper + * return code is returned. + */ +#define CONTEXT_CREATE \ + ASSERT_RC(getdns_context_create(&context, TRUE), \ + GETDNS_RETURN_GOOD, \ + "Return code from getdns_context_create()"); + +/* + * The EVENT_BASE_CREATE macro is used to + * create an event base and put it in the + * context. + */ +#define EVENT_BASE_CREATE \ + event_base = event_base_new(); \ + ck_assert_msg(event_base != NULL, "Event base creation failed"); \ + ASSERT_RC(getdns_extension_set_libevent_base(context, event_base), \ + GETDNS_RETURN_GOOD, \ + "Return code from getdns_extension_set_libevent_base()"); + +/* + * The EVENT_LOOP macro calls the event loop. + */ +#define EVENT_LOOP \ + int dispatch_return = event_base_dispatch(event_base); + +/* + * The process_response macro declares the + * variables needed to house the response and + * calls the function that extracts it. + */ +#define EXTRACT_RESPONSE \ + struct extracted_response ex_response; \ + extract_response(response, &ex_response); + +void extract_response(struct getdns_dict *response, struct extracted_response *ex_response); +void assert_noerror(struct extracted_response *ex_response); +void assert_nodata(struct extracted_response *ex_response); +void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa); +void assert_nxdomain(struct extracted_response *ex_response); +void assert_soa_in_authority(struct extracted_response *ex_response); +void assert_ptr_in_answer(struct extracted_response *ex_response); +void negative_callbackfn( + struct getdns_context *context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id +); +void positive_callbackfn( + struct getdns_context *context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id +); + +START_TEST (getdns_general_1) +{ + /* + * context = NULL + * expect: GETDNS_RETURN_BAD_CONTEXT + */ + STANDARD_TEST_DECLARATIONS; + ASSERT_RC(getdns_general(context, "google.com", GETDNS_RRTYPE_A, NULL, + "getdns_general_1", &transaction_id, negative_callbackfn), + GETDNS_RETURN_BAD_CONTEXT, "Return code from getdns_general()"); +} +END_TEST + +START_TEST (getdns_general_2) +{ + /* + * name = NULL + * expect: GETDNS_RETURN_GENERIC_ERROR + */ + STANDARD_TEST_DECLARATIONS; + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, NULL, GETDNS_RRTYPE_A, NULL, + "getdns_general_2", &transaction_id, negative_callbackfn), + GETDNS_RETURN_GENERIC_ERROR, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_3) +{ + /* + * name = invalid domain (too many octets) + * expect: GETDNS_RETURN_BAD_DOMAIN_NAME + */ + STANDARD_TEST_DECLARATIONS; + const char *name = "oh.my.gosh.and.for.petes.sake.are.you.fricking.crazy.man.because.this.spectacular.and.elaborately.thought.out.domain.name.of.very.significant.length.is.just.too.darn.long.because.you.know.the rfc.states.that.two.hundred.fifty.five.characters.is.the.max.com"; + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, name, GETDNS_RRTYPE_A, NULL, + "getdns_general_3", &transaction_id, negative_callbackfn), + GETDNS_RETURN_BAD_DOMAIN_NAME, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_4) +{ + /* + * name = invalid domain (label too long) + * expect: GETDNS_RETURN_BAD_DOMAIN_NAME + */ + STANDARD_TEST_DECLARATIONS; + const char *name = "this.domain.hasalabelwhichexceedsthemaximumdnslabelsizeofsixtythreecharacters.com"; + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, name, GETDNS_RRTYPE_A, NULL, + "getdns_general_4", &transaction_id, negative_callbackfn), + GETDNS_RETURN_BAD_DOMAIN_NAME, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_5) +{ + /* + * callbackfn = NULL + * expect: GETDNS_RETURN_GENERIC_ERROR + */ + STANDARD_TEST_DECLARATIONS; + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", GETDNS_RRTYPE_A, NULL, + "getdns_general_5", &transaction_id, NULL), + GETDNS_RETURN_GENERIC_ERROR, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_6) +{ + /* + * name = "google.com" + * request_type = 0 (minimum valid RRTYPE) + * expect: NOERROR/NODATA response: + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount = 0 (number of records in ANSWER section) + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", 0, NULL, + "getdns_general_6", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_7) +{ + /* + * name = "google.com" + * request_type = 65279 (maximum unassigned RRTYPE) + * expect: NOERROR/NODATA response: + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount = 0 (number of records in ANSWER section) + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", 65279, NULL, + "getdns_general_7", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_8) +{ + /* + * name = "google.com" + * request_type = GETDNS_RRTYPE_A + * expect: NOERROR response with A records + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount >= 1 (number of records in ANSWER section) + * and equals number of A records ("type": 1) in "answer" list + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", GETDNS_RRTYPE_A, NULL, + "getdns_general_8", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_9) +{ + /* + * name = "google.com" + * request_type = GETDNS_RRTYPE_AAAA + * expect: NOERROR response with AAAA records + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount >= 1 (number of records in ANSWER section) + * and equals number of AAAA records ("type": 28) in "answer" list + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", GETDNS_RRTYPE_AAAA, NULL, + "getdns_general_9", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_10) +{ + /* + * name = "thisdomainsurelydoesntexist.com" + * request_type = GETDNS_RRTYPE_TXT` + * expect: NXDOMAIN response with SOA record + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 3 + * ancount = 0 (number of records in ANSWER section) + * nscount = 1 (number of records in AUTHORITY section) + * and SOA record ("type": 6) present in "authority" list + */ + STANDARD_TEST_DECLARATIONS; + const char *name = "thisdomainsurelydoesntexist.com"; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, name, GETDNS_RRTYPE_TXT, NULL, + "getdns_general_10", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_11) +{ + /* + * name = "hampster.com" need to replace this with domain from unbound zone + * request_type = GETDNS_RRTYPE_MX + * expect: NOERROR/NODATA response: + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount = 0 (number of records in ANSWER section) + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "hampster.com", GETDNS_RRTYPE_MX, NULL, + "getdns_general_11", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_12) +{ + /* + * name = "google.com" need to swap this out for max domain name length with max lable length` + * request_type = GETDNS_RRTYPE_A + * expect: NOERROR response with A records + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount >= 1 (number of records in ANSWER section) + * and equals number of A records ("type": 1) in "answer" list + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "google.com", GETDNS_RRTYPE_A, NULL, + "getdns_general_12", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_13) +{ + /* + * name = "75.101.146.66" need to change this to local unbound data + * request_type = GETDNS_RRTYPE_PTR + * expect: NOERROR response with PTR record + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount == 1 (number of records in ANSWER section) + * and PTR record found ("type": 12) in "answer" list + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "75.101.146.66", GETDNS_RRTYPE_PTR, NULL, + "getdns_general_13", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +START_TEST (getdns_general_14) +{ + /* + * name = "2607:f8b0:4006:802::1007" need to change this to local unbound data + * request_type = GETDNS_RRTYPE_PTR + * expect: NOERROR response with PTR record + * status = GETDNS_RESPSTATUS_GOOD + * rcode = 0 + * ancount == 1 (number of records in ANSWER section) + * and PTR record found ("type": 12) in "answer" list + */ + STANDARD_TEST_DECLARATIONS; + + CONTEXT_CREATE; + EVENT_BASE_CREATE; + ASSERT_RC(getdns_general(context, "2607:f8b0:4006:802::1007", GETDNS_RRTYPE_PTR, NULL, + "getdns_general_14", &transaction_id, positive_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_general()"); + EVENT_LOOP; +} +END_TEST + +Suite * +getdns_general_suite (void) +{ + Suite *s = suite_create ("getdns_general()"); + + /* Negative test caseis */ + TCase *tc_neg = tcase_create("Negative"); + tcase_add_test(tc_neg, getdns_general_1); + tcase_add_test(tc_neg, getdns_general_2); + tcase_add_test(tc_neg, getdns_general_3); + tcase_add_test(tc_neg, getdns_general_4); + tcase_add_test(tc_neg, getdns_general_5); + suite_add_tcase(s, tc_neg); + + /* Positive test cases */ + TCase *tc_pos = tcase_create("Positive"); + tcase_add_test(tc_pos, getdns_general_6); + tcase_add_test(tc_pos, getdns_general_7); + tcase_add_test(tc_pos, getdns_general_8); + tcase_add_test(tc_pos, getdns_general_9); + tcase_add_test(tc_pos, getdns_general_10); + tcase_add_test(tc_pos, getdns_general_11); + tcase_add_test(tc_pos, getdns_general_12); + tcase_add_test(tc_pos, getdns_general_13); + tcase_add_test(tc_pos, getdns_general_14); + suite_add_tcase(s, tc_pos); + + return s; +} + +/* + * extract_response extracts all of the various information + * a test may want to look at from the response. + */ +void extract_response(struct getdns_dict *response, struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + + ck_assert_msg(response != NULL, "Response should not be NULL"); + + ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type), + GETDNS_RETURN_GOOD, "Failed to extract \"top answer_type\""); + + ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name), + GETDNS_RETURN_GOOD, "Failed to extract \"top canonical_name\""); + + ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers), + GETDNS_RETURN_GOOD, "Failed to extract \"just_address_answers\""); + ck_assert_msg(ex_response->just_address_answers != NULL, "just_address_answers should not be NULL"); + + ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full), + GETDNS_RETURN_GOOD, "Failed to extract \"replies_full\""); + ck_assert_msg(ex_response->replies_full != NULL, "replies_full should not be NULL"); + + ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree), + GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree\""); + ck_assert_msg(ex_response->replies_tree != NULL, "replies_tree should not be NULL"); + + ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict), + GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree[0]\""); + ck_assert_msg(ex_response->replies_tree_sub_dict != NULL, "replies_tree[0] dict should not be NULL"); + + ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "additional", &ex_response->additional), + GETDNS_RETURN_GOOD, "Failed to extract \"additional\""); + ck_assert_msg(ex_response->additional != NULL, "additional should not be NULL"); + + ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\""); + ck_assert_msg(ex_response->answer != NULL, "answer should not be NULL"); + + ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type), + GETDNS_RETURN_GOOD, "Failed to extract \"answer_type\""); + + ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority), + GETDNS_RETURN_GOOD, "Failed to extract \"authority\""); + ck_assert_msg(ex_response->authority != NULL, "authority should not be NULL"); + + ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name), + GETDNS_RETURN_GOOD, "Failed to extract \"canonical_name\""); + + ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header), + GETDNS_RETURN_GOOD, "Failed to extract \"header\""); + ck_assert_msg(ex_response->header != NULL, "header should not be NULL"); + + ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question), + GETDNS_RETURN_GOOD, "Failed to extract \"question\""); + ck_assert_msg(ex_response->question != NULL, "question should not be NULL"); + + ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status), + GETDNS_RETURN_GOOD, "Failed to extract \"status\""); +} + +/* + * assert_noerror asserts that the rcode is 0 + */ +void assert_noerror(struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t rcode; + + ASSERT_RC(ex_response->status, GETDNS_RESPSTATUS_GOOD, "Unexpected value for \"status\""); + ASSERT_RC(getdns_dict_get_int(ex_response->header, "rcode", &rcode), GETDNS_RETURN_GOOD, "Failed to extract \"rcode\""); + ck_assert_msg(rcode == 0, "Expected rcode == 0, got %d", rcode); +} + +/* + * assert_nodata asserts that ancount in the header and the + * of the answer section (list) are both zero. + */ +void assert_nodata(struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t ancount; + size_t length; + + ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount), + GETDNS_RETURN_GOOD, "Failed to extract \"ancount\""); + ck_assert_msg(ancount == 0, "Expected ancount == 0, got %d", ancount); + + ASSERT_RC(getdns_list_get_length(ex_response->answer, &length), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length"); + ck_assert_msg(length == 0, "Expected \"answer\" length == 0, got %d", length); +} + +/* + * assert_address_records_in_answer asserts that ancount in the header + * is >= 1, ancount is equal to the length of "answer", and that all of + * the records in the answer section are A and/or AAAA resource records + * based on the value of the a/aaaa arguments. + */ +void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t ancount; + size_t length; + struct getdns_dict *rr_dict; + uint32_t type; + uint32_t address_records = 0; + + ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount), + GETDNS_RETURN_GOOD, "Failed to extract \"ancount\""); + ck_assert_msg(ancount >= 1, "Expected ancount >= 1, got %d", ancount); + + ASSERT_RC(getdns_list_get_length(ex_response->answer, &length), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length"); + ck_assert_msg(length == ancount, "Expected \"answer\" length == ancount: %d, got %d", ancount, length); + + for(size_t i = 0; i < length; i++) + { + ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record"); + ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type), + GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record"); + switch (type) + { + case GETDNS_RRTYPE_A: + if(a && type == GETDNS_RRTYPE_A) + address_records++; + case GETDNS_RRTYPE_AAAA: + if(aaaa && type == GETDNS_RRTYPE_AAAA) + address_records++; + } + } + ck_assert_msg(ancount == address_records, "ancount: %d address records mismatch: %d", + ancount, address_records); +} + +/* + * assert_nxdomain asserts that an NXDOMAIN response was + * was returned for the DNS query meaning: + * rcode == 3 + */ +void assert_nxdomain(struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t rcode; + + ASSERT_RC(ex_response->status, GETDNS_RESPSTATUS_GOOD, "Unexpected value for \"status\""); + ASSERT_RC(getdns_dict_get_int(ex_response->header, "rcode", &rcode), GETDNS_RETURN_GOOD, "Failed to extract \"rcode\""); + ck_assert_msg(rcode == 3, "Expected rcode == 0, got %d", rcode); +} + +/* + * assert_soa_in_authority asserts that a SOA record was + * returned in the authority sections. + */ +void assert_soa_in_authority(struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t nscount; + size_t length; + struct getdns_dict *rr_dict; + uint32_t type; + uint32_t soa_records = 0; + + ASSERT_RC(getdns_dict_get_int(ex_response->header, "nscount", &nscount), + GETDNS_RETURN_GOOD, "Failed to extract \"nscount\""); + ck_assert_msg(nscount >= 1, "Expected nscount >= 1, got %d", nscount); + + ASSERT_RC(getdns_list_get_length(ex_response->authority, &length), + GETDNS_RETURN_GOOD, "Failed to extract \"authority\" length"); + ck_assert_msg(length == nscount, "Expected \"authority\" length == nscount: %d, got %d", nscount, length); + + for(size_t i = 0; i < length; i++) + { + ASSERT_RC(getdns_list_get_dict(ex_response->authority, i, &rr_dict), + GETDNS_RETURN_GOOD, "Failed to extract \"authority\" record"); + ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type), + GETDNS_RETURN_GOOD, "Failed to extract \"type\" from authority record"); + if(type == GETDNS_RRTYPE_SOA) + soa_records++; + } + + ck_assert_msg(soa_records == 1, "Expected to find one SOA record in authority section, got %d", soa_records); +} + +/* + * assert_ptr_in_answer asserts that a PTR record was + * returned in the answer sections. + */ +void assert_ptr_in_answer(struct extracted_response *ex_response) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + uint32_t ancount; + size_t length; + struct getdns_dict *rr_dict; + uint32_t type; + uint32_t ptr_records = 0; + + ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount), + GETDNS_RETURN_GOOD, "Failed to extract \"nscount\""); + ck_assert_msg(ancount >= 1, "Expected ancount >= 1, got %d", ancount); + + ASSERT_RC(getdns_list_get_length(ex_response->answer, &length), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length"); + ck_assert_msg(length == ancount, "Expected \"answer\" length == ancount: %d, got %d", ancount, length); + + for(size_t i = 0; i < length; i++) + { + ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict), + GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record"); + ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type), + GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record"); + if(type == GETDNS_RRTYPE_PTR) + ptr_records++; + } + + ck_assert_msg(ptr_records == 1, "Expected to find one PTR record in answer section, got %d", ptr_records); +} + +void negative_callbackfn(struct getdns_context *context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id) +{ + ck_abort_msg("Callback should never occur for negative test cases"); +} + +void positive_callbackfn(struct getdns_context *context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id) +{ + size_t buflen = MAXLEN; + char error_string[MAXLEN]; + + ASSERT_RC(callback_type, GETDNS_CALLBACK_COMPLETE, "Callback type"); + EXTRACT_RESPONSE; + + if(strcmp(userarg, "getdns_general_6") == 0 || + strcmp(userarg, "getdns_general_7") == 0 || + strcmp(userarg, "getdns_general_11") == 0) + { + assert_noerror(&ex_response); + assert_nodata(&ex_response); + } + else if(strcmp(userarg, "getdns_general_8") == 0 || + strcmp(userarg, "getdns_general_12") == 0) + { + assert_noerror(&ex_response); + assert_address_in_answer(&ex_response, TRUE, FALSE); + } + else if(strcmp(userarg, "getdns_general_9") == 0) + { + assert_noerror(&ex_response); + assert_address_in_answer(&ex_response, FALSE, TRUE); + } + else if(strcmp(userarg, "getdns_general_10") == 0) + { + assert_nxdomain(&ex_response); + assert_nodata(&ex_response); + assert_soa_in_authority(&ex_response); + } + else if(strcmp(userarg, "getdns_general_13") == 0 || + strcmp(userarg, "getdns_general_14") == 0) + { + printf("DICT:%s\n", getdns_pretty_print_dict(response)); + assert_noerror(&ex_response); + assert_ptr_in_answer(&ex_response); + } + else + { + ck_abort_msg("Unexpected value in userarg: %s", userarg); + } +} + +int +main (void) +{ + int number_failed; + Suite *s = getdns_general_suite(); + SRunner *sr = srunner_create(s); + srunner_set_log(sr, "getdns_general_test.log"); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/test/check_getdns_general_sync.c b/src/test/check_getdns_general_sync.c index 43171873..c474596f 100644 --- a/src/test/check_getdns_general_sync.c +++ b/src/test/check_getdns_general_sync.c @@ -31,7 +31,6 @@ struct extracted_response { * The STANDARD_TEST_DECLARATIONS macro defines * ithe standard variable definitions most tests * will need. - * */ #define STANDARD_TEST_DECLARATIONS \ struct getdns_context *context = NULL; \ @@ -292,7 +291,6 @@ START_TEST (getdns_general_sync_12) ASSERT_RC(getdns_general_sync(context, "google.com", GETDNS_RRTYPE_A, NULL, &response), GETDNS_RETURN_GOOD, "Return code from getdns_general_sync()"); EXTRACT_RESPONSE; - printf("DICT:\n%s\n", getdns_pretty_print_dict(response)); assert_noerror(&ex_response); assert_address_in_answer(&ex_response, TRUE, FALSE); } @@ -315,7 +313,6 @@ START_TEST (getdns_general_sync_13) ASSERT_RC(getdns_general_sync(context, "75.101.146.66", GETDNS_RRTYPE_PTR, NULL, &response), GETDNS_RETURN_GOOD, "Return code from getdns_general_sync()"); EXTRACT_RESPONSE; - printf("DICT:\n%s\n", getdns_pretty_print_dict(response)); assert_noerror(&ex_response); assert_ptr_in_answer(&ex_response); } @@ -356,9 +353,9 @@ getdns_general_sync_suite (void) tcase_add_test(tc_neg, getdns_general_sync_4); tcase_add_test(tc_neg, getdns_general_sync_5); suite_add_tcase(s, tc_neg); + /* Positive test cases */ TCase *tc_pos = tcase_create("Positive"); - tcase_add_test(tc_pos, getdns_general_sync_6); tcase_add_test(tc_pos, getdns_general_sync_7); tcase_add_test(tc_pos, getdns_general_sync_8);