Replaces clock_gettime() with ast_tsnow()
[asterisk/asterisk.git] / tests / test_dns.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Mark Michelson
5  *
6  * Mark Michelson <mmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*** MODULEINFO
20         <depend>TEST_FRAMEWORK</depend>
21         <support_level>core</support_level>
22  ***/
23
24 #include "asterisk.h"
25
26 #include <arpa/nameser.h>
27 #include <arpa/inet.h>
28
29 #include "asterisk/test.h"
30 #include "asterisk/module.h"
31 #include "asterisk/dns_core.h"
32 #include "asterisk/dns_resolver.h"
33 #include "asterisk/dns_internal.h"
34
35 /* Used when a stub is needed for certain tests */
36 static int stub_resolve(struct ast_dns_query *query)
37 {
38         return 0;
39 }
40
41 /* Used when a stub is needed for certain tests */
42 static int stub_cancel(struct ast_dns_query *query)
43 {
44         return 0;
45 }
46
47 AST_TEST_DEFINE(resolver_register_unregister)
48 {
49         struct ast_dns_resolver cool_guy_resolver = {
50                 .name = "A snake that swallowed a deer",
51                 .priority = 19890504,
52                 .resolve = stub_resolve,
53                 .cancel = stub_cancel,
54         };
55
56         switch (cmd) {
57         case TEST_INIT:
58                 info->name = "resolver_register_unregister";
59                 info->category = "/main/dns/";
60                 info->summary = "Test nominal resolver registration and unregistration";
61                 info->description =
62                         "The test performs the following steps:\n"
63                         "\t* Register a valid resolver.\n"
64                         "\t* Unregister the resolver.\n"
65                         "If either step fails, the test fails";
66                 return AST_TEST_NOT_RUN;
67         case TEST_EXECUTE:
68                 break;
69         }
70
71         if (ast_dns_resolver_register(&cool_guy_resolver)) {
72                 ast_test_status_update(test, "Unable to register a perfectly good resolver\n");
73                 return AST_TEST_FAIL;
74         }
75
76         ast_dns_resolver_unregister(&cool_guy_resolver);
77
78         return AST_TEST_PASS;
79 }
80
81 AST_TEST_DEFINE(resolver_register_off_nominal)
82 {
83         struct ast_dns_resolver valid = {
84                 .name = "valid",
85                 .resolve = stub_resolve,
86                 .cancel = stub_cancel,
87         };
88
89         struct ast_dns_resolver incomplete1 = {
90                 .name = NULL,
91                 .resolve = stub_resolve,
92                 .cancel = stub_cancel,
93         };
94
95         struct ast_dns_resolver incomplete2 = {
96                 .name = "incomplete2",
97                 .resolve = NULL,
98                 .cancel = stub_cancel,
99         };
100
101         struct ast_dns_resolver incomplete3 = {
102                 .name = "incomplete3",
103                 .resolve = stub_resolve,
104                 .cancel = NULL,
105         };
106
107         switch (cmd) {
108         case TEST_INIT:
109                 info->name = "resolver_register_off_nominal";
110                 info->category = "/main/dns/";
111                 info->summary = "Test off-nominal resolver registration";
112                 info->description =
113                         "Test off-nominal resolver registration:\n"
114                         "\t* Register a duplicate resolver\n"
115                         "\t* Register a resolver without a name\n"
116                         "\t* Register a resolver without a resolve() method\n"
117                         "\t* Register a resolver without a cancel() method";
118                 return AST_TEST_NOT_RUN;
119         case TEST_EXECUTE:
120                 break;
121         }
122
123         if (ast_dns_resolver_register(&valid)) {
124                 ast_test_status_update(test, "Failed to register valid resolver\n");
125                 return AST_TEST_FAIL;
126         }
127
128         if (!ast_dns_resolver_register(&valid)) {
129                 ast_test_status_update(test, "Successfully registered the same resolver multiple times\n");
130                 return AST_TEST_FAIL;
131         }
132
133         ast_dns_resolver_unregister(&valid);
134
135         if (!ast_dns_resolver_register(NULL)) {
136                 ast_test_status_update(test, "Successfully registered a NULL resolver\n");
137                 return AST_TEST_FAIL;
138         }
139
140         if (!ast_dns_resolver_register(&incomplete1)) {
141                 ast_test_status_update(test, "Successfully registered a DNS resolver with no name\n");
142                 return AST_TEST_FAIL;
143         }
144
145         if (!ast_dns_resolver_register(&incomplete2)) {
146                 ast_test_status_update(test, "Successfully registered a DNS resolver with no resolve() method\n");
147                 return AST_TEST_FAIL;
148         }
149
150         if (!ast_dns_resolver_register(&incomplete3)) {
151                 ast_test_status_update(test, "Successfully registered a DNS resolver with no cancel() method\n");
152                 return AST_TEST_FAIL;
153         }
154
155         return AST_TEST_PASS;
156 }
157
158 AST_TEST_DEFINE(resolver_unregister_off_nominal)
159 {
160         struct ast_dns_resolver non_existent = {
161                 .name = "I do not exist",
162                 .priority = 20141004,
163                 .resolve = stub_resolve,
164                 .cancel = stub_cancel,
165         };
166
167         switch (cmd) {
168         case TEST_INIT:
169                 info->name = "resolver_unregister_off_nominal";
170                 info->category = "/main/dns/";
171                 info->summary = "Test off-nominal DNS resolver unregister";
172                 info->description =
173                         "The test attempts the following:\n"
174                         "\t* Unregister a resolver that is not registered.\n"
175                         "\t* Unregister a NULL pointer.\n"
176                         "Because unregistering a resolver does not return an indicator of success, the best\n"
177                         "this test can do is verify that nothing blows up when this is attempted.";
178                 return AST_TEST_NOT_RUN;
179         case TEST_EXECUTE:
180                 break;
181         }
182
183         ast_dns_resolver_unregister(&non_existent);
184         ast_dns_resolver_unregister(NULL);
185
186         return AST_TEST_PASS;
187 }
188
189 AST_TEST_DEFINE(resolver_data)
190 {
191         struct ast_dns_query some_query;
192
193         struct digits {
194                 int fingers;
195                 int toes;
196         };
197
198         RAII_VAR(struct digits *, average, NULL, ao2_cleanup);
199         RAII_VAR(struct digits *, polydactyl, NULL, ao2_cleanup);
200
201         struct digits *data_ptr;
202
203         switch (cmd) {
204         case TEST_INIT:
205                 info->name = "resolver_data";
206                 info->category = "/main/dns/";
207                 info->summary = "Test getting and setting data on a DNS resolver";
208                 info->description = "This test does the following:\n"
209                         "\t* Ensure that requesting resolver data results in a NULL return if no data has been set.\n"
210                         "\t* Ensure that setting resolver data does not result in an error.\n"
211                         "\t* Ensure that retrieving the set resolver data returns the data we expect\n"
212                         "\t* Ensure that setting new resolver data on the query does not result in an error\n"
213                         "\t* Ensure that retrieving the resolver data returns the new data that we set";
214                 return AST_TEST_NOT_RUN;
215         case TEST_EXECUTE:
216                 break;
217         }
218
219         memset(&some_query, 0, sizeof(some_query));
220
221         average = ao2_alloc(sizeof(*average), NULL);
222         polydactyl = ao2_alloc(sizeof(*average), NULL);
223
224         if (!average || !polydactyl) {
225                 ast_test_status_update(test, "Allocation failure during unit test\n");
226                 return AST_TEST_FAIL;
227         }
228
229         /* Ensure that NULL is retrieved if we haven't set anything on the query */
230         data_ptr = ast_dns_resolver_get_data(&some_query);
231         if (data_ptr) {
232                 ast_test_status_update(test, "Retrieved non-NULL resolver data from query unexpectedly\n");
233                 return AST_TEST_FAIL;
234         }
235
236         if (ast_dns_resolver_set_data(&some_query, average)) {
237                 ast_test_status_update(test, "Failed to set resolver data on query\n");
238                 return AST_TEST_FAIL;
239         }
240
241         /* Go ahead now and remove the query's reference to the resolver data to prevent memory leaks */
242         ao2_ref(average, -1);
243
244         /* Ensure that data can be set and retrieved */
245         data_ptr = ast_dns_resolver_get_data(&some_query);
246         if (!data_ptr) {
247                 ast_test_status_update(test, "Unable to retrieve resolver data from DNS query\n");
248                 return AST_TEST_FAIL;
249         }
250
251         if (data_ptr != average) {
252                 ast_test_status_update(test, "Unexpected resolver data retrieved from DNS query\n");
253                 return AST_TEST_FAIL;
254         }
255
256         /* Ensure that attempting to set new resolver data on the query fails */
257         if (!ast_dns_resolver_set_data(&some_query, polydactyl)) {
258                 ast_test_status_update(test, "Successfully overwrote resolver data on a query. We shouldn't be able to do that\n");
259                 return AST_TEST_FAIL;
260         }
261
262         return AST_TEST_PASS;
263 }
264
265 static int test_results(struct ast_test *test, const struct ast_dns_query *query,
266                 unsigned int expected_secure, unsigned int expected_bogus,
267                 unsigned int expected_rcode, const char *expected_canonical,
268                 const char *expected_answer, size_t answer_size)
269 {
270         struct ast_dns_result *result;
271
272         result = ast_dns_query_get_result(query);
273         if (!result) {
274                 ast_test_status_update(test, "Unable to retrieve result from query\n");
275                 return -1;
276         }
277
278         if (ast_dns_result_get_secure(result) != expected_secure ||
279                         ast_dns_result_get_bogus(result) != expected_bogus ||
280                         ast_dns_result_get_rcode(result) != expected_rcode ||
281                         strcmp(ast_dns_result_get_canonical(result), expected_canonical) ||
282                         memcmp(ast_dns_result_get_answer(result), expected_answer, answer_size)) {
283                 ast_test_status_update(test, "Unexpected values in result from query\n");
284                 return -1;
285         }
286
287         return 0;
288 }
289
290 /* When setting a DNS result, we have to provide the raw DNS answer. This
291  * is not happening. Sorry. Instead, we provide a dummy string and call it
292  * a day
293  */
294 #define DNS_ANSWER "Grumble Grumble"
295 #define DNS_ANSWER_SIZE strlen(DNS_ANSWER)
296
297 AST_TEST_DEFINE(resolver_set_result)
298 {
299         struct ast_dns_query some_query;
300         struct ast_dns_result *result;
301
302         struct dns_result {
303                 unsigned int secure;
304                 unsigned int bogus;
305                 unsigned int rcode;
306         } results[] = {
307                 { 0, 0, ns_r_noerror, },
308                 { 0, 1, ns_r_noerror, },
309                 { 1, 0, ns_r_noerror, },
310                 { 0, 0, ns_r_nxdomain, },
311         };
312         int i;
313         enum ast_test_result_state res = AST_TEST_PASS;
314
315         switch (cmd) {
316         case TEST_INIT:
317                 info->name = "resolver_set_result";
318                 info->category = "/main/dns/";
319                 info->summary = "Test setting and getting results on DNS queries";
320                 info->description =
321                         "This test performs the following:\n"
322                         "\t* Sets a result that is not secure, bogus, and has rcode 0\n"
323                         "\t* Sets a result that is not secure, has rcode 0, but is secure\n"
324                         "\t* Sets a result that is not bogus, has rcode 0, but is secure\n"
325                         "\t* Sets a result that is not secure or bogus, but has rcode NXDOMAIN\n"
326                         "After each result is set, we ensure that parameters retrieved from\n"
327                         "the result have the expected values.";
328                 return AST_TEST_NOT_RUN;
329         case TEST_EXECUTE:
330                 break;
331         }
332
333         memset(&some_query, 0, sizeof(some_query));
334
335         for (i = 0; i < ARRAY_LEN(results); ++i) {
336                 if (ast_dns_resolver_set_result(&some_query, results[i].secure, results[i].bogus,
337                                 results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
338                         ast_test_status_update(test, "Unable to add DNS result to query\n");
339                         res = AST_TEST_FAIL;
340                 }
341
342                 if (test_results(test, &some_query, results[i].secure, results[i].bogus,
343                                 results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
344                         res = AST_TEST_FAIL;
345                 }
346         }
347
348         /* The final result we set needs to be freed */
349         result = ast_dns_query_get_result(&some_query);
350         ast_dns_result_free(result);
351
352         return res;
353 }
354
355 AST_TEST_DEFINE(resolver_set_result_off_nominal)
356 {
357         struct ast_dns_query some_query;
358         struct ast_dns_result *result;
359
360         switch (cmd) {
361         case TEST_INIT:
362                 info->name = "resolver_set_result_off_nominal";
363                 info->category = "/main/dns/";
364                 info->summary = "Test setting off-nominal DNS results";
365                 info->description =
366                         "This test performs the following:\n"
367                         "\t* Attempt to add a DNS result that is both bogus and secure\n"
368                         "\t* Attempt to add a DNS result that has no canonical name\n"
369                         "\t* Attempt to add a DNS result that has no answer\n"
370                         "\t* Attempt to add a DNS result with a zero answer size";
371                 return AST_TEST_NOT_RUN;
372         case TEST_EXECUTE:
373                 break;
374         }
375
376         memset(&some_query, 0, sizeof(some_query));
377
378         if (!ast_dns_resolver_set_result(&some_query, 1, 1, ns_r_noerror, "asterisk.org",
379                                 DNS_ANSWER, DNS_ANSWER_SIZE)) {
380                 ast_test_status_update(test, "Successfully added a result that was both secure and bogus\n");
381                 result = ast_dns_query_get_result(&some_query);
382                 ast_dns_result_free(result);
383                 return AST_TEST_FAIL;
384         }
385
386         if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
387                                 DNS_ANSWER, DNS_ANSWER_SIZE)) {
388                 ast_test_status_update(test, "Successfully added result with no canonical name\n");
389                 result = ast_dns_query_get_result(&some_query);
390                 ast_dns_result_free(result);
391                 return AST_TEST_FAIL;
392         }
393
394         if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
395                                 NULL, DNS_ANSWER_SIZE)) {
396                 ast_test_status_update(test, "Successfully added result with no answer\n");
397                 result = ast_dns_query_get_result(&some_query);
398                 ast_dns_result_free(result);
399                 return AST_TEST_FAIL;
400         }
401
402         if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
403                                 DNS_ANSWER, 0)) {
404                 ast_test_status_update(test, "Successfully added result with answer size of zero\n");
405                 result = ast_dns_query_get_result(&some_query);
406                 ast_dns_result_free(result);
407                 return AST_TEST_FAIL;
408         }
409
410         return AST_TEST_PASS;
411 }
412
413 static int test_record(struct ast_test *test, const struct ast_dns_record *record,
414                 int rr_type, int rr_class, int ttl, const char *data, const size_t size)
415 {
416         if (ast_dns_record_get_rr_type(record) != rr_type) {
417                 ast_test_status_update(test, "Unexpected rr_type from DNS record\n");
418                 return -1;
419         }
420
421         if (ast_dns_record_get_rr_class(record) != rr_class) {
422                 ast_test_status_update(test, "Unexpected rr_class from DNS record\n");
423                 return -1;
424         }
425
426         if (ast_dns_record_get_ttl(record) != ttl) {
427                 ast_test_status_update(test, "Unexpected ttl from DNS record\n");
428                 return -1;
429         }
430
431         if (memcmp(ast_dns_record_get_data(record), data, size)) {
432                 ast_test_status_update(test, "Unexpected data in DNS record\n");
433                 return -1;
434         }
435
436         return 0;
437 }
438
439 AST_TEST_DEFINE(resolver_add_record)
440 {
441         RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
442         struct ast_dns_query some_query;
443         const struct ast_dns_record *record;
444
445         static const char *V4 = "127.0.0.1";
446         static const size_t V4_BUFSIZE = sizeof(struct in_addr);
447         char v4_buf[V4_BUFSIZE];
448
449         static const char *V6 = "::1";
450         static const size_t V6_BUFSIZE = sizeof(struct in6_addr);
451         char v6_buf[V6_BUFSIZE];
452
453         struct dns_record_details {
454                 int type;
455                 int class;
456                 int ttl;
457                 const char *data;
458                 const size_t size;
459                 int visited;
460         } records[] = {
461                 { ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE, 0, },
462                 { ns_t_aaaa, ns_c_in, 12345, v6_buf, V6_BUFSIZE, 0, },
463         };
464
465         int num_records_visited = 0;
466
467         switch (cmd) {
468         case TEST_INIT:
469                 info->name = "resolver_add_record";
470                 info->category = "/main/dns/";
471                 info->summary = "Test adding DNS records to a query";
472                 info->description =
473                         "This test performs the following:\n"
474                         "\t* Ensure a nominal A record can be added to a query result\n"
475                         "\t* Ensures that the record can be retrieved\n"
476                         "\t* Ensure that a second record can be added to the query result\n"
477                         "\t* Ensures that both records can be retrieved";
478                 return AST_TEST_NOT_RUN;
479         case TEST_EXECUTE:
480                 break;
481         }
482
483         memset(&some_query, 0, sizeof(some_query));
484
485         if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org",
486                                 DNS_ANSWER, DNS_ANSWER_SIZE)) {
487                 ast_test_status_update(test, "Unable to set result for DNS query\n");
488                 return AST_TEST_FAIL;
489         }
490
491         result = ast_dns_query_get_result(&some_query);
492         if (!result) {
493                 ast_test_status_update(test, "Unable to retrieve result from query\n");
494                 return AST_TEST_FAIL;
495         }
496
497         inet_pton(AF_INET, V4, v4_buf);
498
499         /* Nominal Record */
500         if (ast_dns_resolver_add_record(&some_query, records[0].type, records[0].class,
501                                 records[0].ttl, records[0].data, records[0].size)) {
502                 ast_test_status_update(test, "Unable to add nominal record to query result\n");
503                 return AST_TEST_FAIL;
504         }
505
506         /* I should only be able to retrieve one record */
507         record = ast_dns_result_get_records(result);
508         if (!record) {
509                 ast_test_status_update(test, "Unable to retrieve record from result\n");
510                 return AST_TEST_FAIL;
511         }
512
513         if (test_record(test, record, records[0].type, records[0].class, records[0].ttl,
514                                 records[0].data, records[0].size)) {
515                 return AST_TEST_FAIL;
516         }
517
518         if (ast_dns_record_get_next(record)) {
519                 ast_test_status_update(test, "Multiple records returned when only one was expected\n");
520                 return AST_TEST_FAIL;
521         }
522
523         inet_pton(AF_INET6, V6, v6_buf);
524
525         if (ast_dns_resolver_add_record(&some_query, records[1].type, records[1].class,
526                                 records[1].ttl, records[1].data, records[1].size)) {
527                 ast_test_status_update(test, "Unable to add second record to query result\n");
528                 return AST_TEST_FAIL;
529         }
530
531         for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
532                 int res;
533
534                 /* The order of returned records is not specified by the API. We use the record type
535                  * as the discriminator to determine which record data to expect.
536                  */
537                 if (ast_dns_record_get_rr_type(record) == records[0].type) {
538                         res = test_record(test, record, records[0].type, records[0].class, records[0].ttl, records[0].data, records[0].size);
539                         records[0].visited = 1;
540                 } else if (ast_dns_record_get_rr_type(record) == records[1].type) {
541                         res = test_record(test, record, records[1].type, records[1].class, records[1].ttl, records[1].data, records[1].size);
542                         records[1].visited = 1;
543                 } else {
544                         ast_test_status_update(test, "Unknown record type found in DNS results\n");
545                         return AST_TEST_FAIL;
546                 }
547
548                 if (res) {
549                         return AST_TEST_FAIL;
550                 }
551
552                 ++num_records_visited;
553         }
554
555         if (!records[0].visited || !records[1].visited) {
556                 ast_test_status_update(test, "Did not visit all added DNS records\n");
557                 return AST_TEST_FAIL;
558         }
559
560         if (num_records_visited != ARRAY_LEN(records)) {
561                 ast_test_status_update(test, "Did not visit the expected number of DNS records\n");
562                 return AST_TEST_FAIL;
563         }
564
565         return AST_TEST_PASS;
566 }
567
568 AST_TEST_DEFINE(resolver_add_record_off_nominal)
569 {
570         RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
571         struct ast_dns_query some_query;
572         static const char *V4 = "127.0.0.1";
573         static const size_t V4_BUFSIZE = sizeof(struct in_addr);
574         char v4_buf[V4_BUFSIZE];
575
576         switch (cmd) {
577         case TEST_INIT:
578                 info->name = "resolver_add_record_off_nominal";
579                 info->category = "/main/dns/";
580                 info->summary = "Test adding off-nominal DNS records to a query";
581                 info->description =
582                         "This test performs the following:\n"
583                         "\t* Ensure a nominal A record cannot be added if no result has been set.\n"
584                         "\t* Ensure that an A record with invalid RR types cannot be added to a query\n"
585                         "\t* Ensure that an A record with invalid RR classes cannot be added to a query\n"
586                         "\t* Ensure that an A record with invalid TTL cannot be added to a query\n"
587                         "\t* Ensure that an A record with NULL data cannot be added to a query\n"
588                         "\t* Ensure that an A record with invalid length cannot be added to a query";
589                 return AST_TEST_NOT_RUN;
590         case TEST_EXECUTE:
591                 break;
592         }
593
594         memset(&some_query, 0, sizeof(some_query));
595
596         inet_ntop(AF_INET, V4, v4_buf, V4_BUFSIZE);
597
598         /* Add record before setting result */
599         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
600                 ast_test_status_update(test, "Successfully added DNS record to query before setting a result\n");
601                 return AST_TEST_FAIL;
602         }
603
604         if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org",
605                                 DNS_ANSWER, DNS_ANSWER_SIZE)) {
606                 ast_test_status_update(test, "Unable to set result for DNS query\n");
607                 return AST_TEST_FAIL;
608         }
609
610         /* We get the result so it will be cleaned up when the function exits */
611         result = ast_dns_query_get_result(&some_query);
612
613         /* Invalid RR types */
614         if (!ast_dns_resolver_add_record(&some_query, -1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
615                 ast_test_status_update(test, "Successfully added DNS record with negative RR type\n");
616                 return AST_TEST_FAIL;
617         }
618
619         if (!ast_dns_resolver_add_record(&some_query, ns_t_max + 1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
620                 ast_test_status_update(test, "Successfully added DNS record with too large RR type\n");
621                 return AST_TEST_FAIL;
622         }
623
624         /* Invalid RR classes */
625         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, -1, 12345, v4_buf, V4_BUFSIZE)) {
626                 ast_test_status_update(test, "Successfully added DNS record with negative RR class\n");
627                 return AST_TEST_FAIL;
628         }
629
630         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_max + 1, 12345, v4_buf, V4_BUFSIZE)) {
631                 ast_test_status_update(test, "Successfully added DNS record with too large RR class\n");
632                 return AST_TEST_FAIL;
633         }
634
635         /* Invalid TTL */
636         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, -1, v4_buf, V4_BUFSIZE)) {
637                 ast_test_status_update(test, "Successfully added DNS record with negative TTL\n");
638                 return AST_TEST_FAIL;
639         }
640
641         /* No data */
642         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, NULL, 0)) {
643                 ast_test_status_update(test, "Successfully added a DNS record with no data\n");
644                 return AST_TEST_FAIL;
645         }
646
647         /* Lie about the length */
648         if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, 0)) {
649                 ast_test_status_update(test, "Successfully added a DNS record with length zero\n");
650                 return AST_TEST_FAIL;
651         }
652
653         return AST_TEST_PASS;
654 }
655
656 /*!
657  * \brief File-scoped data used during resolver tests
658  *
659  * This data has to live at file-scope since it needs to be
660  * accessible by multiple threads.
661  */
662 static struct resolver_data {
663         /*! True if the resolver's resolve() method has been called */
664         int resolve_called;
665         /*! True if the resolver's cancel() method has been called */
666         int canceled;
667         /*! True if resolution successfully completed. This is mutually exclusive with \ref canceled */
668         int resolution_complete;
669         /*! Lock used for protecting \ref cancel_cond */
670         ast_mutex_t lock;
671         /*! Condition variable used to coordinate canceling a query */
672         ast_cond_t cancel_cond;
673 } test_resolver_data;
674
675 /*!
676  * \brief Thread spawned by the mock resolver
677  *
678  * All DNS resolvers are required to be asynchronous. The mock resolver
679  * spawns this thread for every DNS query that is executed.
680  *
681  * This thread waits for 5 seconds and then returns the same A record
682  * every time. The 5 second wait is to allow for the query to be
683  * canceled if desired
684  *
685  * \param dns_query The ast_dns_query that is being resolved
686  * \return NULL
687  */
688 static void *resolution_thread(void *dns_query)
689 {
690         struct ast_dns_query *query = dns_query;
691         struct timespec timeout;
692
693         static const char *V4 = "127.0.0.1";
694         static const size_t V4_BUFSIZE = sizeof(struct in_addr);
695         char v4_buf[V4_BUFSIZE];
696
697         timeout = ast_tsnow();
698         timeout.tv_sec += 5;
699
700         ast_mutex_lock(&test_resolver_data.lock);
701         while (!test_resolver_data.canceled) {
702                 if (ast_cond_timedwait(&test_resolver_data.cancel_cond, &test_resolver_data.lock, &timeout) == ETIMEDOUT) {
703                         break;
704                 }
705         }
706         ast_mutex_unlock(&test_resolver_data.lock);
707
708         if (test_resolver_data.canceled) {
709                 ast_dns_resolver_completed(query);
710                 ao2_ref(query, -1);
711                 return NULL;
712         }
713
714         ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE);
715
716         inet_pton(AF_INET, V4, v4_buf);
717         ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE);
718
719         test_resolver_data.resolution_complete = 1;
720         ast_dns_resolver_completed(query);
721
722         ao2_ref(query, -1);
723         return NULL;
724 }
725
726 /*!
727  * \brief Mock resolver's resolve method
728  *
729  * \param query The query to resolve
730  * \retval 0 Successfully spawned resolution thread
731  * \retval non-zero Failed to spawn the resolution thread
732  */
733 static int test_resolve(struct ast_dns_query *query)
734 {
735         pthread_t resolver_thread;
736
737         test_resolver_data.resolve_called = 1;
738         return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread, ao2_bump(query));
739 }
740
741 /*!
742  * \brief Mock resolver's cancel method
743  *
744  * This signals the resolution thread not to return any DNS results.
745  *
746  * \param query DNS query to cancel
747  * \return 0
748  */
749 static int test_cancel(struct ast_dns_query *query)
750 {
751         ast_mutex_lock(&test_resolver_data.lock);
752         test_resolver_data.canceled = 1;
753         ast_cond_signal(&test_resolver_data.cancel_cond);
754         ast_mutex_unlock(&test_resolver_data.lock);
755
756         return 0;
757 }
758
759 /*!
760  * \brief Initialize global mock resolver data.
761  *
762  * This must be called at the beginning of tests that use the mock resolver
763  */
764 static void resolver_data_init(void)
765 {
766         test_resolver_data.resolve_called = 0;
767         test_resolver_data.canceled = 0;
768         test_resolver_data.resolution_complete = 0;
769
770         ast_mutex_init(&test_resolver_data.lock);
771         ast_cond_init(&test_resolver_data.cancel_cond, NULL);
772 }
773
774 /*!
775  * \brief Cleanup global mock resolver data
776  *
777  * This must be called at the end of tests that use the mock resolver
778  */
779 static void resolver_data_cleanup(void)
780 {
781         ast_mutex_destroy(&test_resolver_data.lock);
782         ast_cond_destroy(&test_resolver_data.cancel_cond);
783 }
784
785 /*!
786  * \brief The mock resolver
787  *
788  * The mock resolver does not care about the DNS query that is
789  * actually being made on it. It simply regurgitates the same
790  * DNS record no matter what.
791  */
792 static struct ast_dns_resolver test_resolver = {
793         .name = "test",
794         .priority = 0,
795         .resolve = test_resolve,
796         .cancel = test_cancel,
797 };
798
799 AST_TEST_DEFINE(resolver_resolve_sync)
800 {
801         RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
802         enum ast_test_result_state res = AST_TEST_PASS;
803
804         switch (cmd) {
805         case TEST_INIT:
806                 info->name = "resolver_resolve_sync";
807                 info->category = "/main/dns/";
808                 info->summary = "Test a nominal synchronous DNS resolution";
809                 info->description =
810                         "This test performs a synchronous DNS resolution of a domain. The goal of this\n"
811                         "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
812                         "the resolver is called into as expected, that the query completes entirely before\n"
813                         "returning from the synchronous resolution, that nothing tried to cancel the resolution\n,"
814                         "and that some records were returned.";
815                 return AST_TEST_NOT_RUN;
816         case TEST_EXECUTE:
817                 break;
818         }
819
820         if (ast_dns_resolver_register(&test_resolver)) {
821                 ast_test_status_update(test, "Unable to register test resolver\n");
822                 return AST_TEST_FAIL;
823         }
824
825         resolver_data_init();
826
827         if (ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) {
828                 ast_test_status_update(test, "Resolution of address failed\n");
829                 res = AST_TEST_FAIL;
830                 goto cleanup;
831         }
832
833         if (!result) {
834                 ast_test_status_update(test, "DNS resolution returned a NULL result\n");
835                 res = AST_TEST_FAIL;
836                 goto cleanup;
837         }
838
839         if (!test_resolver_data.resolve_called) {
840                 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
841                 res = AST_TEST_FAIL;
842                 goto cleanup;
843         }
844
845         if (test_resolver_data.canceled) {
846                 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
847                 res = AST_TEST_FAIL;
848                 goto cleanup;
849         }
850
851         if (!test_resolver_data.resolution_complete) {
852                 ast_test_status_update(test, "Synchronous resolution completed early?\n");
853                 res = AST_TEST_FAIL;
854                 goto cleanup;
855         }
856
857         if (!ast_dns_result_get_records(result)) {
858                 ast_test_status_update(test, "Synchronous resolution yielded no records.\n");
859                 res = AST_TEST_FAIL;
860                 goto cleanup;
861         }
862
863 cleanup:
864         ast_dns_resolver_unregister(&test_resolver);
865         resolver_data_cleanup();
866         return res;
867 }
868
869 /*!
870  * \brief A resolve() method that simply fails
871  *
872  * \param query The DNS query to resolve. This is ignored.
873  * \return -1
874  */
875 static int fail_resolve(struct ast_dns_query *query)
876 {
877         return -1;
878 }
879
880 AST_TEST_DEFINE(resolver_resolve_sync_off_nominal)
881 {
882         struct ast_dns_resolver terrible_resolver = {
883                 .name = "Uwe Boll's Filmography",
884                 .priority = 0,
885                 .resolve = fail_resolve,
886                 .cancel = stub_cancel,
887         };
888
889         struct ast_dns_result *result = NULL;
890
891         struct dns_resolve_data {
892                 const char *name;
893                 int rr_type;
894                 int rr_class;
895                 struct ast_dns_result **result;
896         } resolves [] = {
897                 { NULL,           ns_t_a,       ns_c_in,      &result },
898                 { "asterisk.org", -1,           ns_c_in,      &result },
899                 { "asterisk.org", ns_t_max + 1, ns_c_in,      &result },
900                 { "asterisk.org", ns_t_a,       -1,           &result },
901                 { "asterisk.org", ns_t_a,       ns_c_max + 1, &result },
902                 { "asterisk.org", ns_t_a,       ns_c_in,      NULL },
903         };
904
905         int i;
906
907         enum ast_test_result_state res = AST_TEST_PASS;
908
909         switch (cmd) {
910         case TEST_INIT:
911                 info->name = "resolver_resolve_sync_off_nominal";
912                 info->category = "/main/dns/";
913                 info->summary = "Test off-nominal synchronous DNS resolution";
914                 info->description =
915                         "This test performs several off-nominal synchronous DNS resolutions:\n"
916                         "\t* Attempt resolution with NULL name\n"
917                         "\t* Attempt resolution with invalid RR type\n"
918                         "\t* Attempt resolution with invalid RR class\n"
919                         "\t* Attempt resolution with NULL result pointer\n"
920                         "\t* Attempt resolution with resolver that returns an error";
921                 return AST_TEST_NOT_RUN;
922         case TEST_EXECUTE:
923                 break;
924         }
925
926         if (ast_dns_resolver_register(&test_resolver)) {
927                 ast_test_status_update(test, "Failed to register test resolver\n");
928                 return AST_TEST_FAIL;
929         }
930
931         for (i = 0; i < ARRAY_LEN(resolves); ++i) {
932                 if (!ast_dns_resolve(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class, resolves[i].result)) {
933                         ast_test_status_update(test, "Successfully resolved DNS query with invalid parameters\n");
934                         res = AST_TEST_FAIL;
935                 } else if (result) {
936                         ast_test_status_update(test, "Failed resolution set a non-NULL result\n");
937                         ast_dns_result_free(result);
938                         res = AST_TEST_FAIL;
939                 }
940         }
941
942         ast_dns_resolver_unregister(&test_resolver);
943
944         /* As a final test, try a legitimate query with a bad resolver */
945         if (ast_dns_resolver_register(&terrible_resolver)) {
946                 ast_test_status_update(test, "Failed to register the terrible resolver\n");
947                 return AST_TEST_FAIL;
948         }
949
950         if (!ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) {
951                 ast_test_status_update(test, "DNS resolution succeeded when we expected it not to\n");
952                 ast_dns_resolver_unregister(&terrible_resolver);
953                 return AST_TEST_FAIL;
954         }
955
956         ast_dns_resolver_unregister(&terrible_resolver);
957
958         if (result) {
959                 ast_test_status_update(test, "Failed DNS resolution set the result to something non-NULL\n");
960                 ast_dns_result_free(result);
961                 return AST_TEST_FAIL;
962         }
963
964         return res;
965 }
966
967 /*!
968  * \brief Data used by async result callback
969  *
970  * This is the typical combination of boolean, lock, and condition
971  * used to synchronize the activities of two threads. In this case,
972  * the testing thread waits on the condition, and the async callback
973  * signals the condition when the asynchronous callback is complete.
974  */
975 struct async_resolution_data {
976         int complete;
977         ast_mutex_t lock;
978         ast_cond_t cond;
979 };
980
981 /*!
982  * \brief Destructor for async_resolution_data
983  */
984 static void async_data_destructor(void *obj)
985 {
986         struct async_resolution_data *async_data = obj;
987
988         ast_mutex_destroy(&async_data->lock);
989         ast_cond_destroy(&async_data->cond);
990 }
991
992 /*!
993  * \brief Allocation/initialization for async_resolution_data
994  *
995  * The DNS core mandates that a query's user data has to be ao2 allocated,
996  * so this is a helper method for doing that.
997  *
998  * \retval NULL Failed allocation
999  * \retval non-NULL Newly allocated async_resolution_data
1000  */
1001 static struct async_resolution_data *async_data_alloc(void)
1002 {
1003         struct async_resolution_data *async_data;
1004
1005         async_data = ao2_alloc(sizeof(*async_data), async_data_destructor);
1006         if (!async_data) {
1007                 return NULL;
1008         }
1009
1010         async_data->complete = 0;
1011         ast_mutex_init(&async_data->lock);
1012         ast_cond_init(&async_data->cond, NULL);
1013
1014         return async_data;
1015 }
1016
1017 /*!
1018  * \brief Async DNS callback
1019  *
1020  * This is called when an async query completes, either because it resolved or
1021  * because it was canceled. In our case, this callback is used to signal to the
1022  * test that it can continue
1023  *
1024  * \param query The DNS query that has completed
1025  */
1026 static void async_callback(const struct ast_dns_query *query)
1027 {
1028         struct async_resolution_data *async_data = ast_dns_query_get_data(query);
1029
1030         ast_mutex_lock(&async_data->lock);
1031         async_data->complete = 1;
1032         ast_cond_signal(&async_data->cond);
1033         ast_mutex_unlock(&async_data->lock);
1034 }
1035
1036 AST_TEST_DEFINE(resolver_resolve_async)
1037 {
1038         RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
1039         RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
1040         struct ast_dns_result *result;
1041         enum ast_test_result_state res = AST_TEST_PASS;
1042         struct timespec timeout;
1043
1044         switch (cmd) {
1045         case TEST_INIT:
1046                 info->name = "resolver_resolve_async";
1047                 info->category = "/main/dns/";
1048                 info->summary = "Test a nominal asynchronous DNS resolution";
1049                 info->description =
1050                         "This test performs an asynchronous DNS resolution of a domain. The goal of this\n"
1051                         "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
1052                         "the resolver is called into as expected, that we regain control before the query\n"
1053                         "is completed, and to ensure that nothing tried to cancel the resolution.";
1054                 return AST_TEST_NOT_RUN;
1055         case TEST_EXECUTE:
1056                 break;
1057         }
1058
1059         if (ast_dns_resolver_register(&test_resolver)) {
1060                 ast_test_status_update(test, "Unable to register test resolver\n");
1061                 return AST_TEST_FAIL;
1062         }
1063
1064         resolver_data_init();
1065
1066         async_data = async_data_alloc();
1067         if (!async_data) {
1068                 ast_test_status_update(test, "Failed to allocate asynchronous data\n");
1069                 res = AST_TEST_FAIL;
1070                 goto cleanup;
1071         }
1072
1073         active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data);
1074         if (!active) {
1075                 ast_test_status_update(test, "Asynchronous resolution of address failed\n");
1076                 res = AST_TEST_FAIL;
1077                 goto cleanup;
1078         }
1079
1080         if (!test_resolver_data.resolve_called) {
1081                 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
1082                 res = AST_TEST_FAIL;
1083                 goto cleanup;
1084         }
1085
1086         if (test_resolver_data.canceled) {
1087                 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
1088                 res = AST_TEST_FAIL;
1089                 goto cleanup;
1090         }
1091
1092         timeout = ast_tsnow();
1093         timeout.tv_sec += 10;
1094         ast_mutex_lock(&async_data->lock);
1095         while (!async_data->complete) {
1096                 if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
1097                         break;
1098                 }
1099         }
1100         ast_mutex_unlock(&async_data->lock);
1101
1102         if (!async_data->complete) {
1103                 ast_test_status_update(test, "Asynchronous resolution timed out\n");
1104                 res = AST_TEST_FAIL;
1105                 goto cleanup;
1106         }
1107
1108         if (!test_resolver_data.resolution_complete) {
1109                 ast_test_status_update(test, "Asynchronous resolution completed early?\n");
1110                 res = AST_TEST_FAIL;
1111                 goto cleanup;
1112         }
1113
1114         result = ast_dns_query_get_result(active->query);
1115         if (!result) {
1116                 ast_test_status_update(test, "Asynchronous resolution yielded no result\n");
1117                 res = AST_TEST_FAIL;
1118                 goto cleanup;
1119         }
1120
1121         if (!ast_dns_result_get_records(result)) {
1122                 ast_test_status_update(test, "Asynchronous result had no records\n");
1123                 res = AST_TEST_FAIL;
1124                 goto cleanup;
1125         }
1126
1127 cleanup:
1128         ast_dns_resolver_unregister(&test_resolver);
1129         resolver_data_cleanup();
1130         return res;
1131 }
1132
1133 /*! Stub async resolution callback */
1134 static void stub_callback(const struct ast_dns_query *query)
1135 {
1136         return;
1137 }
1138
1139 AST_TEST_DEFINE(resolver_resolve_async_off_nominal)
1140 {
1141         struct ast_dns_resolver terrible_resolver = {
1142                 .name = "Ed Wood's Filmography",
1143                 .priority = 0,
1144                 .resolve = fail_resolve,
1145                 .cancel = stub_cancel,
1146         };
1147
1148         struct dns_resolve_data {
1149                 const char *name;
1150                 int rr_type;
1151                 int rr_class;
1152                 ast_dns_resolve_callback callback;
1153         } resolves [] = {
1154                 { NULL,           ns_t_a,       ns_c_in,      stub_callback },
1155                 { "asterisk.org", -1,           ns_c_in,      stub_callback },
1156                 { "asterisk.org", ns_t_max + 1, ns_c_in,      stub_callback },
1157                 { "asterisk.org", ns_t_a,       -1,           stub_callback },
1158                 { "asterisk.org", ns_t_a,       ns_c_max + 1, stub_callback },
1159                 { "asterisk.org", ns_t_a,       ns_c_in,      NULL },
1160         };
1161
1162         struct ast_dns_query_active *active;
1163         enum ast_test_result_state res = AST_TEST_PASS;
1164         int i;
1165
1166         switch (cmd) {
1167         case TEST_INIT:
1168                 info->name = "resolver_resolve_async_off_nominal";
1169                 info->category = "/main/dns/";
1170                 info->summary = "Test off-nominal asynchronous DNS resolution";
1171                 info->description =
1172                         "This test performs several off-nominal asynchronous DNS resolutions:\n"
1173                         "\t* Attempt resolution with NULL name\n"
1174                         "\t* Attempt resolution with invalid RR type\n"
1175                         "\t* Attempt resolution with invalid RR class\n"
1176                         "\t* Attempt resolution with NULL callback pointer\n"
1177                         "\t* Attempt resolution with resolver that returns an error";
1178                 return AST_TEST_NOT_RUN;
1179         case TEST_EXECUTE:
1180                 break;
1181         }
1182
1183         if (ast_dns_resolver_register(&test_resolver)) {
1184                 ast_test_status_update(test, "Failed to register test resolver\n");
1185                 return AST_TEST_FAIL;
1186         }
1187
1188         for (i = 0; i < ARRAY_LEN(resolves); ++i) {
1189                 active = ast_dns_resolve_async(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class,
1190                                 resolves[i].callback, NULL);
1191                 if (active) {
1192                         ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
1193                         ao2_ref(active, -1);
1194                         res = AST_TEST_FAIL;
1195                 }
1196         }
1197
1198         ast_dns_resolver_unregister(&test_resolver);
1199
1200         if (ast_dns_resolver_register(&terrible_resolver)) {
1201                 ast_test_status_update(test, "Failed to register the DNS resolver\n");
1202                 return AST_TEST_FAIL;
1203         }
1204
1205         active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, stub_callback, NULL);
1206
1207         ast_dns_resolver_unregister(&terrible_resolver);
1208
1209         if (active) {
1210                 ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
1211                 ao2_ref(active, -1);
1212                 return AST_TEST_FAIL;
1213         }
1214
1215         return res;
1216 }
1217
1218 AST_TEST_DEFINE(resolver_resolve_async_cancel)
1219 {
1220         RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
1221         RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
1222         struct ast_dns_result *result;
1223         enum ast_test_result_state res = AST_TEST_PASS;
1224         struct timespec timeout;
1225
1226         switch (cmd) {
1227         case TEST_INIT:
1228                 info->name = "resolver_resolve_async_cancel";
1229                 info->category = "/main/dns/";
1230                 info->summary = "Test canceling an asynchronous DNS resolution";
1231                 info->description =
1232                         "This test performs an asynchronous DNS resolution of a domain and then cancels\n"
1233                         "the resolution. The goal of this test is to ensure that the cancel() callback of\n"
1234                         "the resolver is called and that it properly interrupts the resolution such that no\n"
1235                         "records are returned.";
1236                 return AST_TEST_NOT_RUN;
1237         case TEST_EXECUTE:
1238                 break;
1239         }
1240
1241         if (ast_dns_resolver_register(&test_resolver)) {
1242                 ast_test_status_update(test, "Unable to register test resolver\n");
1243                 return AST_TEST_FAIL;
1244         }
1245
1246         resolver_data_init();
1247
1248         async_data = async_data_alloc();
1249         if (!async_data) {
1250                 ast_test_status_update(test, "Failed to allocate asynchronous data\n");
1251                 res = AST_TEST_FAIL;
1252                 goto cleanup;
1253         }
1254
1255         active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data);
1256         if (!active) {
1257                 ast_test_status_update(test, "Asynchronous resolution of address failed\n");
1258                 res = AST_TEST_FAIL;
1259                 goto cleanup;
1260         }
1261
1262         if (!test_resolver_data.resolve_called) {
1263                 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
1264                 res = AST_TEST_FAIL;
1265                 goto cleanup;
1266         }
1267
1268         if (test_resolver_data.canceled) {
1269                 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
1270                 res = AST_TEST_FAIL;
1271                 goto cleanup;
1272         }
1273
1274         ast_dns_resolve_cancel(active);
1275
1276         if (!test_resolver_data.canceled) {
1277                 ast_test_status_update(test, "Resolver's cancel() method was not called\n");
1278                 res = AST_TEST_FAIL;
1279                 goto cleanup;
1280         }
1281
1282         timeout = ast_tsnow();
1283         timeout.tv_sec += 10;
1284         ast_mutex_lock(&async_data->lock);
1285         while (!async_data->complete) {
1286                 if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
1287                         break;
1288                 }
1289         }
1290         ast_mutex_unlock(&async_data->lock);
1291
1292         if (!async_data->complete) {
1293                 ast_test_status_update(test, "Asynchronous resolution timed out\n");
1294                 res = AST_TEST_FAIL;
1295                 goto cleanup;
1296         }
1297
1298         if (test_resolver_data.resolution_complete) {
1299                 ast_test_status_update(test, "Resolution completed without cancelation\n");
1300                 res = AST_TEST_FAIL;
1301                 goto cleanup;
1302         }
1303
1304         result = ast_dns_query_get_result(active->query);
1305         if (result) {
1306                 ast_test_status_update(test, "Canceled resolution had a result\n");
1307                 res = AST_TEST_FAIL;
1308                 goto cleanup;
1309         }
1310
1311 cleanup:
1312         ast_dns_resolver_unregister(&test_resolver);
1313         resolver_data_cleanup();
1314         return res;
1315 }
1316
1317 static int unload_module(void)
1318 {
1319         AST_TEST_UNREGISTER(resolver_register_unregister);
1320         AST_TEST_UNREGISTER(resolver_register_off_nominal);
1321         AST_TEST_UNREGISTER(resolver_unregister_off_nominal);
1322         AST_TEST_UNREGISTER(resolver_data);
1323         AST_TEST_UNREGISTER(resolver_set_result);
1324         AST_TEST_UNREGISTER(resolver_set_result_off_nominal);
1325         AST_TEST_UNREGISTER(resolver_add_record);
1326         AST_TEST_UNREGISTER(resolver_add_record_off_nominal);
1327         AST_TEST_UNREGISTER(resolver_resolve_sync);
1328         AST_TEST_UNREGISTER(resolver_resolve_sync_off_nominal);
1329         AST_TEST_UNREGISTER(resolver_resolve_async);
1330         AST_TEST_UNREGISTER(resolver_resolve_async_off_nominal);
1331         AST_TEST_UNREGISTER(resolver_resolve_async_cancel);
1332
1333         return 0;
1334 }
1335
1336 static int load_module(void)
1337 {
1338         AST_TEST_REGISTER(resolver_register_unregister);
1339         AST_TEST_REGISTER(resolver_register_off_nominal);
1340         AST_TEST_REGISTER(resolver_unregister_off_nominal);
1341         AST_TEST_REGISTER(resolver_data);
1342         AST_TEST_REGISTER(resolver_set_result);
1343         AST_TEST_REGISTER(resolver_set_result_off_nominal);
1344         AST_TEST_REGISTER(resolver_add_record);
1345         AST_TEST_REGISTER(resolver_add_record_off_nominal);
1346         AST_TEST_REGISTER(resolver_resolve_sync);
1347         AST_TEST_REGISTER(resolver_resolve_sync_off_nominal);
1348         AST_TEST_REGISTER(resolver_resolve_async);
1349         AST_TEST_REGISTER(resolver_resolve_async_off_nominal);
1350         AST_TEST_REGISTER(resolver_resolve_async_cancel);
1351
1352         return AST_MODULE_LOAD_SUCCESS;
1353 }
1354
1355 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DNS API Tests");