Author: mmichelson Date: Wed Mar 4 12:50:24 2015 New Revision: 432452 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=432452 Log: Commit progress on some unit tests.
I decided to make this commit now to save some progress made on unit tests. In addition, this makes a few DNS API changes: * Structures are defined in dns_internal.h. This is useful for unit tests that wish to create DNS queries without having to perform a resolution. * Some parameters have been constified. Added: team/group/dns/include/asterisk/dns_internal.h (with props) team/group/dns/tests/test_dns.c (with props) Modified: team/group/dns/include/asterisk/dns_resolver.h team/group/dns/main/dns_core.c Added: team/group/dns/include/asterisk/dns_internal.h URL: http://svnview.digium.com/svn/asterisk/team/group/dns/include/asterisk/dns_internal.h?view=auto&rev=432452 ============================================================================== --- team/group/dns/include/asterisk/dns_internal.h (added) +++ team/group/dns/include/asterisk/dns_internal.h Wed Mar 4 12:50:24 2015 @@ -1,0 +1,109 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Digium, Inc. + * + * Joshua Colp <jc...@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Internal DNS structure definitions + * + * \author Joshua Colp <jc...@digium.com> + */ + +/*! \brief Generic DNS record information */ +struct ast_dns_record { + /*! \brief Resource record type */ + int rr_type; + /*! \brief Resource record class */ + int rr_class; + /*! \brief Time-to-live of the record */ + int ttl; + /*! \brief The raw DNS record */ + char *data; + /*! \brief The size of the raw DNS record */ + size_t data_len; + /*! \brief Linked list information */ + AST_LIST_ENTRY(ast_dns_record) list; +}; + +/*! \brief An SRV record */ +struct ast_dns_srv_record { + /*! \brief Generic DNS record information */ + struct ast_dns_record generic; + /*! \brief The hostname in the SRV record */ + const char *host; + /*! \brief The priority of the SRV record */ + unsigned short priority; + /*! \brief The weight of the SRV record */ + unsigned short weight; + /*! \brief The port in the SRV record */ + unsigned short port; +}; + +/*! \brief A NAPTR record */ +struct ast_dns_naptr_record { + /*! \brief Generic DNS record information */ + struct ast_dns_record generic; + /*! \brief The flags from the NAPTR record */ + const char *flags; + /*! \brief The service from the NAPTR record */ + const char *service; + /*! \brief The regular expression from the NAPTR record */ + const char *regexp; + /*! \brief The replacement from the NAPTR record */ + const char *replacement; + /*! \brief The order for the NAPTR record */ + unsigned short order; + /*! \brief The preference of the NAPTR record */ + unsigned short preference; +}; + +/*! \brief The result of a DNS query */ +struct ast_dns_result { + /*! \brief Whether the domain was not found */ + unsigned int nxdomain; + /*! \brief Whether the result is secure */ + unsigned int secure; + /*! \brief Whether the result is bogus */ + unsigned int bogus; + /*! \brief The canonical name */ + const char *canonical; + /*! \brief Records returned */ + AST_LIST_HEAD_NOLOCK(, ast_dns_record) records; +}; + +/*! \brief A DNS query */ +struct ast_dns_query { + /*! \brief Callback to invoke upon completion */ + ast_dns_resolve_callback callback; + /*! \brief User-specific data */ + void *user_data; + /*! \brief The resolver in use for this query */ + struct ast_dns_resolver *resolver; + /*! \brief Resolver-specific data */ + void *resolver_data; + /*! \brief Result of the DNS query */ + struct ast_dns_result *result; + /*! \brief Timer for recurring resolution */ + int timer; + /*! \brief Resource record type */ + int rr_type; + /*! \brief Resource record class */ + int rr_class; + /*! \brief The name of what is being resolved */ + char name[0]; +}; + Propchange: team/group/dns/include/asterisk/dns_internal.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: team/group/dns/include/asterisk/dns_internal.h ------------------------------------------------------------------------------ svn:keywords = 'Author Date Id Revision' Propchange: team/group/dns/include/asterisk/dns_internal.h ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: team/group/dns/include/asterisk/dns_resolver.h URL: http://svnview.digium.com/svn/asterisk/team/group/dns/include/asterisk/dns_resolver.h?view=diff&rev=432452&r1=432451&r2=432452 ============================================================================== --- team/group/dns/include/asterisk/dns_resolver.h (original) +++ team/group/dns/include/asterisk/dns_resolver.h Wed Mar 4 12:50:24 2015 @@ -86,7 +86,7 @@ * \retval 0 success * \retval -1 failure */ -int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, char *data, size_t size); +int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size); /*! * \brief Mark a DNS query as having been completed Modified: team/group/dns/main/dns_core.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns/main/dns_core.c?view=diff&rev=432452&r1=432451&r2=432452 ============================================================================== --- team/group/dns/main/dns_core.c (original) +++ team/group/dns/main/dns_core.c Wed Mar 4 12:50:24 2015 @@ -40,92 +40,9 @@ #include "asterisk/dns_srv.h" #include "asterisk/dns_tlsa.h" #include "asterisk/dns_resolver.h" +#include "asterisk/dns_internal.h" AST_RWLIST_HEAD_STATIC(resolvers, ast_dns_resolver); - -/*! \brief Generic DNS record information */ -struct ast_dns_record { - /*! \brief Resource record type */ - int rr_type; - /*! \brief Resource record class */ - int rr_class; - /*! \brief Time-to-live of the record */ - int ttl; - /*! \brief The raw DNS record */ - char *data; - /*! \brief The size of the raw DNS record */ - size_t data_len; - /*! \brief Linked list information */ - AST_LIST_ENTRY(ast_dns_record) list; -}; - -/*! \brief An SRV record */ -struct ast_dns_srv_record { - /*! \brief Generic DNS record information */ - struct ast_dns_record generic; - /*! \brief The hostname in the SRV record */ - const char *host; - /*! \brief The priority of the SRV record */ - unsigned short priority; - /*! \brief The weight of the SRV record */ - unsigned short weight; - /*! \brief The port in the SRV record */ - unsigned short port; -}; - -/*! \brief A NAPTR record */ -struct ast_dns_naptr_record { - /*! \brief Generic DNS record information */ - struct ast_dns_record generic; - /*! \brief The flags from the NAPTR record */ - const char *flags; - /*! \brief The service from the NAPTR record */ - const char *service; - /*! \brief The regular expression from the NAPTR record */ - const char *regexp; - /*! \brief The replacement from the NAPTR record */ - const char *replacement; - /*! \brief The order for the NAPTR record */ - unsigned short order; - /*! \brief The preference of the NAPTR record */ - unsigned short preference; -}; - -/*! \brief The result of a DNS query */ -struct ast_dns_result { - /*! \brief Whether the domain was not found */ - unsigned int nxdomain; - /*! \brief Whether the result is secure */ - unsigned int secure; - /*! \brief Whether the result is bogus */ - unsigned int bogus; - /*! \brief The canonical name */ - const char *canonical; - /*! \brief Records returned */ - AST_LIST_HEAD_NOLOCK(, ast_dns_record) records; -}; - -/*! \brief A DNS query */ -struct ast_dns_query { - /*! \brief Callback to invoke upon completion */ - ast_dns_resolve_callback callback; - /*! \brief User-specific data */ - void *user_data; - /*! \brief The resolver in use for this query */ - struct ast_dns_resolver *resolver; - /*! \brief Resolver-specific data */ - void *resolver_data; - /*! \brief Result of the DNS query */ - struct ast_dns_result *result; - /*! \brief Timer for recurring resolution */ - int timer; - /*! \brief Resource record type */ - int rr_type; - /*! \brief Resource record class */ - int rr_class; - /*! \brief The name of what is being resolved */ - char name[0]; -}; const char *ast_dns_query_get_name(const struct ast_dns_query *query) { @@ -426,7 +343,7 @@ query->result = NULL; } -int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, char *data, size_t size) +int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size) { if (!query->result) { return -1; @@ -509,4 +426,4 @@ AST_RWLIST_UNLOCK(&resolvers); ast_verb(2, "Unregistered DNS resolver '%s'\n", resolver->name); -} +} Added: team/group/dns/tests/test_dns.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns/tests/test_dns.c?view=auto&rev=432452 ============================================================================== --- team/group/dns/tests/test_dns.c (added) +++ team/group/dns/tests/test_dns.c Wed Mar 4 12:50:24 2015 @@ -1,0 +1,384 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2015, Mark Michelson + * + * Mark Michelson <mmichel...@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + <depend>TEST_FRAMEWORK</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +#include <arpa/nameser.h> + +#include "asterisk/test.h" +#include "asterisk/module.h" +#include "asterisk/dns_core.h" +#include "asterisk/dns_resolver.h" +#include "asterisk/dns_internal.h" + +/* Used when a stub is needed for certain tests */ +static int stub_resolve(struct ast_dns_query *query) +{ + return 0; +} + +/* Used when a stub is needed for certain tests */ +static int stub_cancel(struct ast_dns_query *query) +{ + return 0; +} + +AST_TEST_DEFINE(resolver_register_unregister) +{ + struct ast_dns_resolver cool_guy_resolver = { + .name = "A snake that swallowed a deer", + .priority = 19890504, + .resolve = stub_resolve, + .cancel = stub_cancel, + }; + + switch (cmd) { + case TEST_INIT: + info->name = "resolver_register_unregister"; + info->category = "/main/dns/"; + info->summary = "Test nominal resolver registration and unregistration"; + info->description = + "The test performs the following steps:\n" + "\t* Register a valid resolver.\n" + "\t* Unregister the resolver.\n" + "If either step fails, the test fails\n"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_dns_resolver_register(&cool_guy_resolver)) { + ast_test_status_update(test, "Unable to register a perfectly good resolver\n"); + return AST_TEST_FAIL; + } + + ast_dns_resolver_unregister(&cool_guy_resolver); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(resolver_register_off_nominal) +{ + struct ast_dns_resolver valid = { + .name = "valid", + .resolve = stub_resolve, + .cancel = stub_cancel, + }; + + struct ast_dns_resolver incomplete1 = { + .name = NULL, + .resolve = stub_resolve, + .cancel = stub_cancel, + }; + + struct ast_dns_resolver incomplete2 = { + .name = "incomplete2", + .resolve = NULL, + .cancel = stub_cancel, + }; + + struct ast_dns_resolver incomplete3 = { + .name = "incomplete3", + .resolve = stub_resolve, + .cancel = NULL, + }; + + switch (cmd) { + case TEST_INIT: + info->name = "resolver_register_off_nominal"; + info->category = "/main/dns/"; + info->summary = "Test off-nominal resolver registration"; + info->description = + "Test off-nominal resolver registration:\n" + "\t* Register a duplicate resolver\n" + "\t* Register a resolver without a name\n" + "\t* Register a resolver without a resolve() method\n" + "\t* Register a resolver without a cancel() method\n"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + if (ast_dns_resolver_register(&valid)) { + ast_test_status_update(test, "Failed to register valid resolver\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_register(&valid)) { + ast_test_status_update(test, "Successfully registered the same resolver multiple times\n"); + return AST_TEST_FAIL; + } + + ast_dns_resolver_unregister(&valid); + + if (!ast_dns_resolver_register(NULL)) { + ast_test_status_update(test, "Successfully registered a NULL resolver\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_register(&incomplete1)) { + ast_test_status_update(test, "Successfully registered a DNS resolver with no name\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_register(&incomplete2)) { + ast_test_status_update(test, "Successfully registered a DNS resolver with no resolve() method\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_register(&incomplete3)) { + ast_test_status_update(test, "Successfully registered a DNS resolver with no cancel() method\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(resolver_unregister_off_nominal) +{ + struct ast_dns_resolver non_existent = { + .name = "I do not exist", + .priority = 20141004, + .resolve = stub_resolve, + .cancel = stub_cancel, + }; + + switch (cmd) { + case TEST_INIT: + info->name = "resolver_unregister_off_nominal"; + info->category = "/main/dns/"; + info->summary = "Test off-nominal DNS resolver unregister"; + info->description = + "The test attempts the following:\n" + "\t* Unregister a resolver that is not registered.\n" + "\t* Unregister a NULL pointer.\n" + "Because unregistering a resolver does not return an indicator of success, the best\n" + "this test can do is verify that nothing blows up when this is attempted.\n"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_dns_resolver_unregister(&non_existent); + ast_dns_resolver_unregister(NULL); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(resolver_data) +{ + struct ast_dns_query some_query; + + struct digits { + int fingers; + int toes; + }; + + struct digits average = { + .fingers = 10, + .toes = 10, + }; + + struct digits polydactyl = { + .fingers = 12, + .toes = 10, + }; + + struct digits *data_ptr; + + switch (cmd) { + case TEST_INIT: + info->name = "resolver_data"; + info->category = "/main/dns/"; + info->summary = "Test getting and setting data on a DNS resolver"; + /* XXX Better description required */ + info->description = "Sup dawg"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + memset(&some_query, 0, sizeof(some_query)); + + /* Ensure that NULL is retrieved if we haven't set anything on the query */ + data_ptr = ast_dns_resolver_get_data(&some_query); + if (data_ptr) { + ast_test_status_update(test, "Retrieved non-NULL resolver data from query unexpectedly\n"); + return AST_TEST_FAIL; + } + + ast_dns_resolver_set_data(&some_query, &average); + + /* Ensure that data can be set and retrieved */ + data_ptr = ast_dns_resolver_get_data(&some_query); + if (!data_ptr) { + ast_test_status_update(test, "Unable to retrieve resolver data from DNS query\n"); + return AST_TEST_FAIL; + } + + if (data_ptr->fingers != average.fingers || data_ptr->toes != average.toes) { + ast_test_status_update(test, "Unexpected resolver data retrieved from DNS query\n"); + return AST_TEST_FAIL; + } + + /* Ensure that we can set new resolver data even if there already is resolver data on the query */ + ast_dns_resolver_set_data(&some_query, &polydactyl); + + data_ptr = ast_dns_resolver_get_data(&some_query); + if (!data_ptr) { + ast_test_status_update(test, "Unable to retrieve resolver data from DNS query\n"); + return AST_TEST_FAIL; + } + + if (data_ptr->fingers != polydactyl.fingers || data_ptr->toes != polydactyl.toes) { + ast_test_status_update(test, "Unexpected resolver data retrieved from DNS query\n"); + return AST_TEST_FAIL; + } + + /* Ensure that ast_dns_resolver_completed() removes resolver data from the query */ + ast_dns_resolver_completed(&some_query); + + data_ptr = ast_dns_resolver_get_data(&some_query); + if (data_ptr) { + ast_test_status_update(test, "Query still has resolver data after query completed\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(resolver_add_record) +{ + struct ast_dns_query some_query; + /* XXX I know this isn't what an A record looks like, but just trying to get something compiling right now */ + static const char *CLEAN_ADDR = "127.0.0.1"; + + switch (cmd) { + case TEST_INIT: + /* XXX Add details */ + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + memset(&some_query, 0, sizeof(some_query)); + + /* Nominal Record */ + if (ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Unable to add nominal record to query\n"); + return AST_TEST_FAIL; + } + + /* Invalid RR types */ + if (!ast_dns_resolver_add_record(&some_query, -1, ns_c_in, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Successfully added DNS record with negative RR type\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_add_record(&some_query, ns_t_max + 1, ns_c_in, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Successfully added DNS record with too large RR type\n"); + return AST_TEST_FAIL; + } + + /* Invalid RR classes */ + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, -1, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Successfully added DNS record with negative RR class\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_max + 1, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Successfully added DNS record with too large RR class\n"); + return AST_TEST_FAIL; + } + + /* Invalid TTL */ + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, -1, CLEAN_ADDR, strlen(CLEAN_ADDR))) { + ast_test_status_update(test, "Successfully added DNS record with negative TTL\n"); + return AST_TEST_FAIL; + } + + /* No data */ + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, NULL, 0)) { + ast_test_status_update(test, "Successfully added a DNS record with no data\n"); + return AST_TEST_FAIL; + } + + /* Lie about the length */ + /* XXX I don't know how valid these tests actually are. */ + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, CLEAN_ADDR, 0)) { + ast_test_status_update(test, "Successfully added a DNS record with length zero\n"); + return AST_TEST_FAIL; + } + + if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, CLEAN_ADDR, strlen(CLEAN_ADDR) * 3)) { + ast_test_status_update(test, "Successfully added a DNS record with overly-large length\n"); + return AST_TEST_FAIL; + } + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(resolver_set_result) +{ + struct ast_dns_query some_query; + + switch (cmd) { + case TEST_INIT: + /* XXX Add details */ + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + memset(&some_query, 0, sizeof(some_query)); + + /* XXX Not sure what to set for canonical on results */ + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(resolver_register_unregister); + AST_TEST_UNREGISTER(resolver_register_off_nominal); + AST_TEST_UNREGISTER(resolver_unregister_off_nominal); + AST_TEST_UNREGISTER(resolver_data); + AST_TEST_UNREGISTER(resolver_add_record); + AST_TEST_UNREGISTER(resolver_set_result); + + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(resolver_register_unregister); + AST_TEST_REGISTER(resolver_register_off_nominal); + AST_TEST_REGISTER(resolver_unregister_off_nominal); + AST_TEST_REGISTER(resolver_data); + AST_TEST_REGISTER(resolver_add_record); + AST_TEST_REGISTER(resolver_set_result); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DNS API Tests"); Propchange: team/group/dns/tests/test_dns.c ------------------------------------------------------------------------------ svn:eol-style = native Propchange: team/group/dns/tests/test_dns.c ------------------------------------------------------------------------------ svn:keywords = 'Author Date Id Revision' Propchange: team/group/dns/tests/test_dns.c ------------------------------------------------------------------------------ svn:mime-type = text/plain -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits