[asterisk-commits] mmichelson: branch group/dns r432662 - in /team/group/dns: main/ tests/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Mar 9 15:26:59 CDT 2015
Author: mmichelson
Date: Mon Mar 9 15:26:57 2015
New Revision: 432662
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=432662
Log:
Add nominal recurring DNS test.
This test ensures that queries recur at the expected interval.
There is an additional change to the DNS core. TTL was being interpreted
as milliseconds instead of seconds when scheduling the recurring queries.
Added:
team/group/dns/tests/test_dns_recurring.c (with props)
Modified:
team/group/dns/main/dns_core.c
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=432662&r1=432661&r2=432662
==============================================================================
--- team/group/dns/main/dns_core.c (original)
+++ team/group/dns/main/dns_core.c Mon Mar 9 15:26:57 2015
@@ -545,7 +545,7 @@
int ttl = dns_query_recurring_get_ttl(query);
if (ttl) {
- recurring->timer = ast_sched_add(sched, ttl, dns_query_recurring_scheduled_callback, ao2_bump(recurring));
+ recurring->timer = ast_sched_add(sched, ttl * 1000, dns_query_recurring_scheduled_callback, ao2_bump(recurring));
if (recurring->timer < 0) {
ao2_ref(recurring, -1);
}
Added: team/group/dns/tests/test_dns_recurring.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns/tests/test_dns_recurring.c?view=auto&rev=432662
==============================================================================
--- team/group/dns/tests/test_dns_recurring.c (added)
+++ team/group/dns/tests/test_dns_recurring.c Mon Mar 9 15:26:57 2015
@@ -1,0 +1,288 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2015, Mark Michelson
+ *
+ * Mark Michelson <mmichelson at 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 <arpa/inet.h>
+
+#include "asterisk/test.h"
+#include "asterisk/module.h"
+#include "asterisk/dns_core.h"
+#include "asterisk/dns_resolver.h"
+#include "asterisk/dns_recurring.h"
+#include "asterisk/dns_internal.h"
+
+struct recurring_data {
+ /*! TTL to place in first returned result */
+ int ttl1;
+ /*! TTL to place in second returned result */
+ int ttl2;
+ /*! Boolean indicator if query has completed */
+ int query_complete;
+ /*! Number of times recurring resolution has completed */
+ int complete_resolutions;
+ /*! Number of times resolve() method has been called */
+ int resolves;
+ ast_mutex_t lock;
+ ast_cond_t cond;
+};
+
+static void recurring_data_destructor(void *obj)
+{
+ struct recurring_data *rdata = obj;
+
+ ast_mutex_destroy(&rdata->lock);
+ ast_cond_destroy(&rdata->cond);
+}
+
+static struct recurring_data *recurring_data_alloc(void)
+{
+ struct recurring_data *rdata;
+
+ rdata = ao2_alloc(sizeof(*rdata), recurring_data_destructor);
+ if (!rdata) {
+ return NULL;
+ }
+
+ ast_mutex_init(&rdata->lock);
+ ast_cond_init(&rdata->cond, NULL);
+
+ return rdata;
+}
+
+static void *resolution_thread(void *dns_query)
+{
+ struct ast_dns_query *query = dns_query;
+
+ static const char *ADDR1 = "127.0.0.1";
+ static const size_t ADDR1_BUFSIZE = sizeof(struct in_addr);
+ char addr1_buf[ADDR1_BUFSIZE];
+
+ static const char *ADDR2 = "192.168.0.1";
+ static const size_t ADDR2_BUFSIZE = sizeof(struct in_addr);
+ char addr2_buf[ADDR2_BUFSIZE];
+
+ struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
+ struct recurring_data *rdata = recurring->user_data;
+
+ ast_assert(rdata != NULL);
+
+ ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org");
+
+ inet_pton(AF_INET, ADDR1, addr1_buf);
+ ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, rdata->ttl1, addr1_buf, ADDR1_BUFSIZE);
+
+ inet_pton(AF_INET, ADDR2, addr2_buf);
+ ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, rdata->ttl2, addr2_buf, ADDR2_BUFSIZE);
+
+ ++rdata->complete_resolutions;
+
+ ast_dns_resolver_completed(query);
+
+ ao2_ref(query, -1);
+ return NULL;
+}
+
+static int recurring_resolve(struct ast_dns_query *query)
+{
+ struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
+ struct recurring_data *rdata = recurring->user_data;
+ pthread_t resolver_thread;
+
+ ast_assert(rdata != NULL);
+ ++rdata->resolves;
+ return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread, ao2_bump(query));
+}
+
+static int recurring_cancel(struct ast_dns_query *query)
+{
+ /* XXX STUB */
+ return 0;
+}
+
+static struct ast_dns_resolver recurring_resolver = {
+ .name = "test_recurring",
+ .priority = 0,
+ .resolve = recurring_resolve,
+ .cancel = recurring_cancel,
+};
+
+static int wait_for_resolution(struct ast_test *test, struct recurring_data *rdata,
+ int expected_lapse, int num_completed)
+{
+ struct timespec begin;
+ struct timespec end;
+ struct timespec timeout;
+ int secdiff;
+
+ clock_gettime(CLOCK_REALTIME, &begin);
+
+ timeout.tv_sec = begin.tv_sec + 20;
+ timeout.tv_nsec = begin.tv_nsec;
+
+ ast_mutex_lock(&rdata->lock);
+ while (!rdata->query_complete) {
+ if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
+ break;
+ }
+ }
+ ast_mutex_unlock(&rdata->lock);
+
+ if (!rdata->query_complete) {
+ ast_test_status_update(test, "Query timed out\n");
+ return -1;
+ }
+
+ rdata->query_complete = 0;
+ clock_gettime(CLOCK_REALTIME, &end);
+
+ secdiff = end.tv_sec - begin.tv_sec;
+
+ /* Give ourselves some wiggle room */
+ if (secdiff < expected_lapse - 2 || secdiff > expected_lapse + 2) {
+ ast_test_status_update(test, "Query did not complete in expected time\n");
+ return -1;
+ }
+
+ if (rdata->resolves != rdata->complete_resolutions && rdata->resolves != num_completed) {
+ ast_test_status_update(test, "Query has not undergone expected number of resolutions\n");
+ return -1;
+ }
+
+ ast_test_status_update(test, "Query completed in expected time frame\n");
+
+ return 0;
+}
+
+static void async_callback(const struct ast_dns_query *query)
+{
+ struct recurring_data *rdata = ast_dns_query_get_data(query);
+
+ ast_assert(rdata != NULL);
+
+ ast_mutex_lock(&rdata->lock);
+ rdata->query_complete = 1;
+ ast_cond_signal(&rdata->cond);
+ ast_mutex_unlock(&rdata->lock);
+}
+
+AST_TEST_DEFINE(recurring_query)
+{
+ RAII_VAR(struct ast_dns_query_recurring *, recurring_query, NULL, ao2_cleanup);
+ RAII_VAR(struct recurring_data *, rdata, NULL, ao2_cleanup);
+
+ enum ast_test_result_state res = AST_TEST_PASS;
+ int expected_lapse;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "recurring_query";
+ info->category = "/main/dns/recurring/";
+ info->summary = "Test nominal asynchronous recurring DNS queries\n";
+ info->description =
+ "This tests nominal recurring queries in the following ways:\n"
+ "\t* An asynchronous query is sent to a mock resolver\n"
+ "\t* The mock resolver returns two records with different TTLs\n"
+ "\t* We ensure that the query re-occurs according to the lower of the TTLs\n"
+ "\t* The mock resolver returns two records, this time with different TTLs\n"
+ "\t from the first time the query was resolved\n"
+ "\t* We ensure that the query re-occurs according to the new lower TTL\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (ast_dns_resolver_register(&recurring_resolver)) {
+ ast_test_status_update(test, "Failed to register recurring DNS resolver\n");
+ return AST_TEST_FAIL;
+ }
+
+ rdata = recurring_data_alloc();
+ if (!rdata) {
+ ast_test_status_update(test, "Failed to allocate data necessary for recurring test\n");
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+
+ expected_lapse = 0;
+ rdata->ttl1 = 5;
+ rdata->ttl2 = 20;
+
+ recurring_query = ast_dns_resolve_recurring("asterisk.org", ns_t_a, ns_c_in, async_callback, rdata);
+ if (!recurring_query) {
+ ast_test_status_update(test, "Failed to create recurring DNS query\n");
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+
+ /* This should be near instantaneous */
+ if (wait_for_resolution(test, rdata, expected_lapse, 1)) {
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+
+ expected_lapse = rdata->ttl1;
+ rdata->ttl1 = 45;
+ rdata->ttl2 = 10;
+
+ /* This should take approximately 5 seconds */
+ if (wait_for_resolution(test, rdata, expected_lapse, 2)) {
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+
+ expected_lapse = rdata->ttl2;
+
+ /* This should take approximately 10 seconds */
+ if (wait_for_resolution(test, rdata, expected_lapse, 3)) {
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+
+cleanup:
+ if (recurring_query) {
+ /* XXX I don't like calling this here since I'm not testing
+ * canceling recurring queries, but I'm forced into it here
+ */
+ ast_dns_resolve_recurring_cancel(recurring_query);
+ }
+ ast_dns_resolver_unregister(&recurring_resolver);
+ return res;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(recurring_query);
+
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(recurring_query);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Recurring DNS query tests");
Propchange: team/group/dns/tests/test_dns_recurring.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/group/dns/tests/test_dns_recurring.c
------------------------------------------------------------------------------
svn:keywords = 'Author Date Id Revision'
Propchange: team/group/dns/tests/test_dns_recurring.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list