57 #include <sys/types.h>
68 static const char *
const test_result2str[] = {
69 [AST_TEST_NOT_RUN] =
"NOT RUN",
70 [AST_TEST_PASS] =
"PASS",
71 [AST_TEST_FAIL] =
"FAIL",
88 enum ast_test_result_state
state;
91 ast_test_init_cb_t *init_cb;
92 ast_test_cleanup_cb_t *cleanup_cb;
97 static struct ast_test_execute_results {
98 unsigned int total_tests;
99 unsigned int total_passed;
100 unsigned int total_failed;
101 unsigned int total_time;
102 unsigned int last_passed;
103 unsigned int last_failed;
104 unsigned int last_time;
110 TEST_NAME_CATEGORY = 2,
113 #define zfclose(fp) \
114 ({ if (fp != NULL) { \
129 #define movefd(oldfd, newfd) \
130 ({ if (oldfd != newfd) { \
131 dup2(oldfd, newfd); \
138 #define lowerfd(oldfd) \
139 ({ int newfd = dup(oldfd); \
152 static struct ast_test *test_alloc(ast_test_cb_t *cb);
153 static struct ast_test *test_free(
struct ast_test *
test);
154 static int test_insert(
struct ast_test *
test);
155 static struct ast_test *test_remove(ast_test_cb_t *cb);
156 static int test_cat_cmp(
const char *cat1,
const char *cat2);
157 static int registration_errors = 0;
159 void ast_test_debug(
struct ast_test *
test,
const char *fmt, ...)
180 int __ast_test_status_update(
const char *file,
const char *func,
int line,
struct ast_test *test,
const char *fmt, ...)
194 ast_cli(test->cli->fd,
"[%s:%s:%d]: %s",
206 int ast_test_register_init(
const char *category, ast_test_init_cb_t *cb)
208 struct ast_test *test;
213 if (!(test_cat_cmp(test->info.category, category))) {
223 int ast_test_register_cleanup(
const char *category, ast_test_cleanup_cb_t *cb)
225 struct ast_test *test;
230 if (!(test_cat_cmp(test->info.category, category))) {
231 test->cleanup_cb = cb;
240 int ast_test_register(ast_test_cb_t *cb)
242 struct ast_test *test;
245 ast_log(LOG_ERROR,
"Attempted to register test without all required information\n");
246 registration_errors++;
250 if (!(test = test_alloc(cb))) {
251 registration_errors++;
255 if (test_insert(test)) {
257 registration_errors++;
264 int ast_test_unregister(ast_test_cb_t *cb)
266 struct ast_test *test;
268 if (!(test = test_remove(cb))) {
284 static void test_execute(
struct ast_test *test)
286 struct timeval begin;
287 enum ast_test_result_state result;
292 if (test->init_cb && test->init_cb(&test->info, test)) {
293 test->state = AST_TEST_FAIL;
296 test->state = AST_TEST_NOT_RUN;
297 result = test->cb(&test->info, TEST_EXECUTE, test);
298 if (test->state != AST_TEST_FAIL) {
299 test->state = result;
301 if (test->cleanup_cb && test->cleanup_cb(&test->info, test)) {
302 test->state = AST_TEST_FAIL;
308 void ast_test_set_result(
struct ast_test *test,
enum ast_test_result_state state)
310 if (test->state == AST_TEST_FAIL || state == AST_TEST_NOT_RUN) {
329 ast_std_free(capture->
outbuf);
331 ast_std_free(capture->
errbuf);
338 int ast_test_capture_command(
struct ast_test_capture *capture,
const char *file,
char *
const argv[],
const char *data,
unsigned datalen)
340 int fd0[2] = { -1, -1 }, fd1[2] = { -1, -1 }, fd2[2] = { -1, -1 };
343 FILE *cmd = NULL, *out = NULL, *err = NULL;
345 ast_test_capture_init(capture);
347 if (data != NULL && datalen > 0) {
348 if (pipe(fd0) == -1) {
349 ast_log(LOG_ERROR,
"Couldn't open stdin pipe: %s\n", strerror(errno));
352 fcntl(fd0[1], F_SETFL, fcntl(fd0[1], F_GETFL, 0) | O_NONBLOCK);
354 if ((fd0[0] = open(
"/dev/null", O_RDONLY)) == -1) {
355 ast_log(LOG_ERROR,
"Couldn't open /dev/null: %s\n", strerror(errno));
360 if (pipe(fd1) == -1) {
361 ast_log(LOG_ERROR,
"Couldn't open stdout pipe: %s\n", strerror(errno));
365 if (pipe(fd2) == -1) {
366 ast_log(LOG_ERROR,
"Couldn't open stderr pipe: %s\n", strerror(errno));
373 if ((pid = fork()) == -1) {
374 ast_log(LOG_ERROR,
"Failed to fork(): %s\n", strerror(errno));
377 }
else if (pid == 0) {
388 ast_log(LOG_ERROR,
"Failed to execv(): %s\n", strerror(errno));
393 int wstatus, n, nfds;
394 fd_set readfds, writefds;
405 if ((cmd = fmemopen(buf,
sizeof(buf),
"w")) == NULL) {
406 ast_log(LOG_ERROR,
"Failed to open memory buffer: %s\n", strerror(errno));
410 for (i = 0; argv[i] != NULL; ++i) {
418 ast_log(LOG_TRACE,
"run: %.*s\n", (
int)
sizeof(buf), buf);
420 if ((out = open_memstream(&capture->
outbuf, &capture->
outlen)) == NULL) {
421 ast_log(LOG_ERROR,
"Failed to open output buffer: %s\n", strerror(errno));
426 if ((err = open_memstream(&capture->
errbuf, &capture->
errlen)) == NULL) {
427 ast_log(LOG_ERROR,
"Failed to open error buffer: %s\n", strerror(errno));
433 n = waitpid(pid, &wstatus, WNOHANG);
435 if (n == pid && WIFEXITED(wstatus)) {
443 capture->
exitcode = WEXITSTATUS(wstatus);
445 ast_log(LOG_TRACE,
"run: pid %d exits %d\n", capture->
pid, capture->
exitcode);
454 nfds = MAX(fd0[1], MAX(fd1[0], fd2[0])) + 1;
460 if (data != NULL && datalen > 0)
461 FD_SET(fd0[1], &writefds);
464 FD_SET(fd1[0], &readfds);
467 FD_SET(fd2[0], &readfds);
473 n = select(nfds, &readfds, &writefds, NULL, NULL);
476 #define SAFE_FD_ISSET(fd, setptr) ((fd) != -1 && FD_ISSET((fd), setptr))
478 if (SAFE_FD_ISSET(fd0[1], &writefds)) {
479 n = write(fd0[1], data, datalen);
482 datalen -= MIN(datalen, n);
491 if (SAFE_FD_ISSET(fd1[0], &readfds)) {
492 n = read(fd1[0], buf,
sizeof(buf));
494 fwrite(buf,
sizeof(
char), n, out);
500 if (SAFE_FD_ISSET(fd2[0], &readfds)) {
501 n = read(fd2[0], buf,
sizeof(buf));
503 fwrite(buf,
sizeof(
char), n, err);
534 static char *reserved_words[] = {
535 "abstract",
"arguments",
"as",
"assert",
"await",
536 "boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
537 "const",
"continue",
"debugger",
"def",
"default",
"delete",
"do",
538 "double",
"else",
"enum",
"eval",
"export",
"extends",
"false",
539 "final",
"finally",
"float",
"for",
"function",
"goto",
"if",
540 "implements",
"import",
"in",
"instanceof",
"int",
"interface",
541 "let",
"long",
"native",
"new",
"null",
"package",
"private",
542 "protected",
"public",
"return",
"short",
"static",
"strictfp",
543 "string",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
544 "trait",
"transient",
"true",
"try",
"typeof",
"var",
"void",
545 "volatile",
"while",
"with",
"yield" };
547 static int is_reserved_word(
const char *word)
551 for (i = 0; i < ARRAY_LEN(reserved_words); i++) {
552 if (strcmp(word, reserved_words[i]) == 0) {
560 static void test_xml_entry(
struct ast_test *test, FILE *f)
563 char *test_cat =
ast_strdupa(test->info.category + 1);
565 char *test_name = (
char *)test->info.name;
568 if (!category || test->state == AST_TEST_NOT_RUN) {
577 if (is_reserved_word(next_cat)) {
586 if (is_reserved_word(test->info.name)) {
587 size_t name_length = strlen(test->info.name) + 2;
590 snprintf(test_name, name_length,
"_%s", test->info.name);
593 fprintf(f,
"\t\t<testcase time=\"%u.%u\" classname=\"%s\" name=\"%s\"%s>\n",
594 test->time / 1000, test->time % 1000,
596 test->state == AST_TEST_PASS ?
"/" :
"");
600 if (test->state == AST_TEST_FAIL) {
601 fprintf(f,
"\t\t\t<failure><![CDATA[\n%s\n\t\t]]></failure>\n",
603 fprintf(f,
"\t\t</testcase>\n");
608 static void test_txt_entry(
struct ast_test *test, FILE *f)
614 fprintf(f,
"\nName: %s\n", test->info.name);
615 fprintf(f,
"Category: %s\n", test->info.category);
616 fprintf(f,
"Summary: %s\n", test->info.summary);
617 fprintf(f,
"Description: %s\n", test->info.description);
618 fprintf(f,
"Result: %s\n", test_result2str[test->state]);
619 if (test->state != AST_TEST_NOT_RUN) {
620 fprintf(f,
"Time: %u\n", test->time);
622 if (test->state == AST_TEST_FAIL) {
623 fprintf(f,
"Error Description: %s\n\n",
S_OR(
ast_str_buffer(test->status_str),
"NA"));
642 static int test_execute_multiple(
const char *name,
const char *category,
struct ast_cli_args *cli)
644 char result_buf[32] = { 0 };
645 struct ast_test *test = NULL;
646 enum test_mode mode = TEST_ALL;
650 if (!ast_strlen_zero(category)) {
651 if (!ast_strlen_zero(name)) {
652 mode = TEST_NAME_CATEGORY;
654 mode = TEST_CATEGORY;
660 memset(&last_results, 0,
sizeof(last_results));
666 if (!test_cat_cmp(test->info.category, category) && !test->info.explicit_only) {
670 case TEST_NAME_CATEGORY:
671 if (!(test_cat_cmp(test->info.category, category)) && !(strcmp(test->info.name, name))) {
676 execute = !test->info.explicit_only;
681 ast_cli(cli->fd,
"START %s - %s \n", test->info.category, test->info.name);
693 last_results.last_time += test->time;
694 if (test->state == AST_TEST_PASS) {
695 last_results.last_passed++;
696 }
else if (test->state == AST_TEST_FAIL) {
697 last_results.last_failed++;
702 test_result2str[test->state],
703 (test->state == AST_TEST_FAIL) ? COLOR_RED : COLOR_GREEN,
706 ast_cli(cli->fd,
"END %s - %s Time: %s%ums Result: %s\n",
709 test->time ?
"" :
"<",
710 test->time ? test->time : 1,
717 last_results.total_time += test->time;
718 if (test->state != AST_TEST_NOT_RUN) {
719 last_results.total_tests++;
720 if (test->state == AST_TEST_PASS) {
721 last_results.total_passed++;
723 last_results.total_failed++;
727 res = last_results.last_passed + last_results.last_failed;
752 static int test_generate_results(
const char *name,
const char *category,
const char *xml_path,
const char *txt_path)
754 enum test_mode mode = TEST_ALL;
755 FILE *f_xml = NULL, *f_txt = NULL;
757 struct ast_test *test = NULL;
760 if (ast_strlen_zero(xml_path) && ast_strlen_zero(txt_path)) {
765 if (!ast_strlen_zero(category)) {
766 if (!ast_strlen_zero(name)) {
767 mode = TEST_NAME_CATEGORY;
769 mode = TEST_CATEGORY;
773 if (!ast_strlen_zero(xml_path)) {
774 if (!(f_xml = fopen(xml_path,
"w"))) {
775 ast_log(LOG_WARNING,
"Could not open file %s for xml test results\n", xml_path);
780 if (!ast_strlen_zero(txt_path)) {
781 if (!(f_txt = fopen(txt_path,
"w"))) {
782 ast_log(LOG_WARNING,
"Could not open file %s for text output of test results\n", txt_path);
794 fprintf(f_xml,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
795 fprintf(f_xml,
"<testsuites>\n");
796 fprintf(f_xml,
"\t<testsuite errors=\"0\" time=\"%u.%u\" tests=\"%u\" failures=\"%u\" "
797 "name=\"AsteriskUnitTests\">\n",
798 last_results.total_time / 1000, last_results.total_time % 1000,
799 last_results.total_tests, last_results.total_failed);
800 fprintf(f_xml,
"\t\t<properties>\n");
801 fprintf(f_xml,
"\t\t\t<property name=\"version\" value=\"%s\"/>\n",
ast_get_version());
802 fprintf(f_xml,
"\t\t</properties>\n");
809 fprintf(f_txt,
"Number of Tests: %u\n", last_results.total_tests);
810 fprintf(f_txt,
"Number of Tests Executed: %u\n", (last_results.total_passed + last_results.total_failed));
811 fprintf(f_txt,
"Passed Tests: %u\n", last_results.total_passed);
812 fprintf(f_txt,
"Failed Tests: %u\n", last_results.total_failed);
813 fprintf(f_txt,
"Total Execution Time: %u\n", last_results.total_time);
820 if (!test_cat_cmp(test->info.category, category)) {
821 test_xml_entry(test, f_xml);
822 test_txt_entry(test, f_txt);
825 case TEST_NAME_CATEGORY:
826 if (!(strcmp(test->info.category, category)) && !(strcmp(test->info.name, name))) {
827 test_xml_entry(test, f_xml);
828 test_txt_entry(test, f_txt);
832 test_xml_entry(test, f_xml);
833 test_txt_entry(test, f_txt);
840 fprintf(f_xml,
"\t</testsuite>\n");
841 fprintf(f_xml,
"</testsuites>\n");
858 static int test_insert(
struct ast_test *test)
878 static struct ast_test *test_remove(ast_test_cb_t *cb)
880 struct ast_test *cur = NULL;
903 static int test_cat_cmp(
const char *cat1,
const char *cat2)
908 if (!cat1 || !cat2) {
919 return strncmp(cat1, cat2, len2) ? 1 : 0;
926 static struct ast_test *test_free(
struct ast_test *test)
932 ast_free(test->status_str);
942 static struct ast_test *test_alloc(ast_test_cb_t *cb)
944 struct ast_test *test;
948 ast_log(LOG_ERROR,
"Failed to allocate test, registration failed.\n");
954 test->cb(&test->info, TEST_INIT, test);
956 if (ast_strlen_zero(test->info.name)) {
957 ast_log(LOG_ERROR,
"Test has no name, test registration refused.\n");
958 return test_free(test);
961 if (ast_strlen_zero(test->info.category)) {
962 ast_log(LOG_ERROR,
"Test %s has no category, test registration refused.\n",
964 return test_free(test);
967 if (test->info.category[0] !=
'/' || test->info.category[strlen(test->info.category) - 1] !=
'/') {
968 ast_log(LOG_WARNING,
"Test category '%s' for test '%s' is missing a leading or trailing slash.\n",
969 test->info.category, test->info.name);
974 ++registration_errors;
977 if (ast_strlen_zero(test->info.summary)) {
978 ast_log(LOG_ERROR,
"Test %s%s has no summary, test registration refused.\n",
979 test->info.category, test->info.name);
980 return test_free(test);
982 if (test->info.summary[strlen(test->info.summary) - 1] ==
'\n') {
983 ast_log(LOG_WARNING,
"Test %s%s summary has a trailing newline.\n",
984 test->info.category, test->info.name);
989 ++registration_errors;
992 if (ast_strlen_zero(test->info.description)) {
993 ast_log(LOG_ERROR,
"Test %s%s has no description, test registration refused.\n",
994 test->info.category, test->info.name);
995 return test_free(test);
997 if (test->info.description[strlen(test->info.description) - 1] ==
'\n') {
998 ast_log(LOG_WARNING,
"Test %s%s description has a trailing newline.\n",
999 test->info.category, test->info.name);
1004 ++registration_errors;
1008 ast_log(LOG_ERROR,
"Failed to allocate status_str for %s%s, test registration failed.\n",
1009 test->info.category, test->info.name);
1010 return test_free(test);
1016 static char *complete_test_category(
const char *word)
1018 int wordlen = strlen(word);
1019 struct ast_test *test;
1023 if (!strncasecmp(word, test->info.category, wordlen)) {
1034 static char *complete_test_name(
const char *word,
const char *category)
1036 int wordlen = strlen(word);
1037 struct ast_test *test;
1041 if (!test_cat_cmp(test->info.category, category) && !strncasecmp(word, test->info.name, wordlen)) {
1055 #define FORMAT "%-25.25s %-30.30s %-40.40s %-13.13s\n"
1056 static const char *
const option1[] = {
"all",
"category", NULL };
1057 static const char *
const option2[] = {
"name", NULL };
1058 struct ast_test *test = NULL;
1062 e->
command =
"test show registered";
1065 "Usage: 'test show registered' can be used in three ways.\n"
1066 " 1. 'test show registered all' shows all registered tests\n"
1067 " 2. 'test show registered category [test category]' shows all tests in the given\n"
1069 " 3. 'test show registered category [test category] name [test name]' shows all\n"
1070 " tests in a given category matching a given name\n";
1076 if (a->pos == 4 && !strcasecmp(a->argv[3],
"category")) {
1077 return complete_test_category(a->word);
1083 return complete_test_name(a->word, a->argv[4]);
1087 if ((a->argc < 4) || (a->argc == 6) || (a->argc > 7) ||
1088 ((a->argc == 4) && strcasecmp(a->argv[3],
"all")) ||
1089 ((a->argc == 7) && strcasecmp(a->argv[5],
"name"))) {
1090 return CLI_SHOWUSAGE;
1092 ast_cli(a->fd, FORMAT,
"Category",
"Name",
"Summary",
"Test Result");
1093 ast_cli(a->fd, FORMAT,
"--------",
"----",
"-------",
"-----------");
1096 if ((a->argc == 4) ||
1097 ((a->argc == 5) && !test_cat_cmp(test->info.category, a->argv[4])) ||
1098 ((a->argc == 7) && !strcmp(test->info.category, a->argv[4]) && !strcmp(test->info.name, a->argv[6]))) {
1100 ast_cli(a->fd, FORMAT, test->info.category, test->info.name,
1101 test->info.summary, test_result2str[test->state]);
1106 ast_cli(a->fd, FORMAT,
"--------",
"----",
"-------",
"-----------");
1107 ast_cli(a->fd,
"\n%d Registered Tests Matched\n", count);
1117 static const char *
const option1[] = {
"all",
"category", NULL };
1118 static const char *
const option2[] = {
"name", NULL };
1124 "Usage: test execute can be used in three ways.\n"
1125 " 1. 'test execute all' runs all registered tests\n"
1126 " 2. 'test execute category [test category]' runs all tests in the given\n"
1128 " 3. 'test execute category [test category] name [test name]' runs all\n"
1129 " tests in a given category matching a given name\n";
1135 if (a->pos == 3 && !strcasecmp(a->argv[2],
"category")) {
1136 return complete_test_category(a->word);
1142 return complete_test_name(a->word, a->argv[3]);
1147 if (a->argc < 3|| a->argc > 6) {
1148 return CLI_SHOWUSAGE;
1151 if ((a->argc == 3) && !strcasecmp(a->argv[2],
"all")) {
1152 ast_cli(a->fd,
"Running all available tests...\n\n");
1153 test_execute_multiple(NULL, NULL, a);
1154 }
else if (a->argc == 4) {
1155 ast_cli(a->fd,
"Running all available tests matching category %s\n\n", a->argv[3]);
1156 test_execute_multiple(NULL, a->argv[3], a);
1157 }
else if (a->argc == 6) {
1158 ast_cli(a->fd,
"Running all available tests matching category %s and name %s\n\n", a->argv[3], a->argv[5]);
1159 test_execute_multiple(a->argv[5], a->argv[3], a);
1161 return CLI_SHOWUSAGE;
1165 if (!(last_results.last_passed + last_results.last_failed)) {
1166 ast_cli(a->fd,
"--- No Tests Found! ---\n");
1168 ast_cli(a->fd,
"\n%u Test(s) Executed %u Passed %u Failed\n",
1169 (last_results.last_passed + last_results.last_failed),
1170 last_results.last_passed,
1171 last_results.last_failed);
1182 #define FORMAT_RES_ALL1 "%s%s %-30.30s %-25.25s %-10.10s\n"
1183 #define FORMAT_RES_ALL2 "%s%s %-30.30s %-25.25s %s%ums\n"
1184 static const char *
const option1[] = {
"all",
"failed",
"passed", NULL };
1185 char result_buf[32] = { 0 };
1186 struct ast_test *test = NULL;
1193 e->
command =
"test show results";
1195 "Usage: test show results can be used in three ways\n"
1196 " 1. 'test show results all' Displays results for all executed tests.\n"
1197 " 2. 'test show results passed' Displays results for all passed tests.\n"
1198 " 3. 'test show results failed' Displays results for all failed tests.\n";
1209 return CLI_SHOWUSAGE;
1210 }
else if (!strcasecmp(a->argv[3],
"passed")) {
1212 }
else if (!strcasecmp(a->argv[3],
"failed")) {
1214 }
else if (!strcasecmp(a->argv[3],
"all")) {
1217 return CLI_SHOWUSAGE;
1220 ast_cli(a->fd, FORMAT_RES_ALL1,
"Result",
"",
"Name",
"Category",
"Time");
1223 if (test->state == AST_TEST_NOT_RUN) {
1226 test->state == AST_TEST_FAIL ? failed++ : passed++;
1227 if (!mode || ((mode == 1) && (test->state == AST_TEST_FAIL)) || ((mode == 2) && (test->state == AST_TEST_PASS))) {
1229 term_color(result_buf, test_result2str[test->state],
1230 (test->state == AST_TEST_FAIL) ? COLOR_RED : COLOR_GREEN,
1231 0,
sizeof(result_buf));
1233 ast_cli(a->fd, FORMAT_RES_ALL2,
1237 test->info.category,
1238 test->time ?
" " :
"<",
1239 test->time ? test->time : 1);
1244 ast_cli(a->fd,
"%d Test(s) Executed %d Passed %d Failed\n", (failed + passed), passed, failed);
1253 static const char *
const option[] = {
"xml",
"txt", NULL };
1254 const char *file = NULL;
1255 const char *type =
"";
1263 e->
command =
"test generate results";
1265 "Usage: 'test generate results'\n"
1266 " Generates test results in either xml or txt format. An optional \n"
1267 " file path may be provided to specify the location of the xml or\n"
1269 " \nExample usage:\n"
1270 " 'test generate results xml' this writes to a default file\n"
1271 " 'test generate results xml /path/to/file.xml' writes to specified file\n";
1281 if (a->argc < 4 || a->argc > 5) {
1282 return CLI_SHOWUSAGE;
1283 }
else if (!strcasecmp(a->argv[3],
"xml")) {
1286 }
else if (!strcasecmp(a->argv[3],
"txt")) {
1289 return CLI_SHOWUSAGE;
1298 ast_str_set(&buf, 0,
"%s/asterisk_test_results-%ld.%s", ast_config_AST_LOG_DIR, (
long) time.tv_sec, type);
1304 res = test_generate_results(NULL, NULL, file, NULL);
1306 res = test_generate_results(NULL, NULL, NULL, file);
1310 ast_cli(a->fd,
"Results Generated Successfully: %s\n",
S_OR(file,
""));
1312 ast_cli(a->fd,
"Results Could Not Be Generated: %s\n",
S_OR(file,
""));
1324 AST_CLI_DEFINE(test_cli_show_registered,
"show registered tests"),
1325 AST_CLI_DEFINE(test_cli_execute_registered,
"execute registered tests"),
1326 AST_CLI_DEFINE(test_cli_show_results,
"show last test results"),
1327 AST_CLI_DEFINE(test_cli_generate_results,
"generate test results to file"),
1332 return test_suite_topic;
1339 struct ast_test_suite_message_payload {
1347 static void test_suite_message_payload_dtor(
void *obj)
1349 struct ast_test_suite_message_payload *payload = obj;
1351 if (payload->blob) {
1356 struct ast_json *ast_test_suite_get_blob(
struct ast_test_suite_message_payload *payload)
1358 return payload->blob;
1364 struct ast_test_suite_message_payload *payload;
1372 blob = ast_test_suite_get_blob(payload);
1378 if (ast_strlen_zero(type) || strcmp(
"testevent", type)) {
1404 .to_ami = test_suite_event_to_ami);
1406 void __ast_test_suite_event_notify(
const char *file,
const char *func,
int line,
const char *state,
const char *fmt, ...)
1408 RAII_VAR(
struct ast_test_suite_message_payload *, payload,
1415 if (!ast_test_suite_message_type()) {
1424 payload = ao2_alloc(
sizeof(*payload), test_suite_message_payload_dtor);
1432 payload->blob =
ast_json_pack(
"{s: s, s: s, s: s, s: s, s: i, s: s}",
1433 "type",
"testevent",
1436 "appfunction", func,
1439 if (!payload->blob) {
1453 info->name =
"registrations";
1454 info->category =
"/main/test/";
1455 info->summary =
"Validate Test Registration Data.";
1456 info->description =
"Validate Test Registration Data.";
1457 return AST_TEST_NOT_RUN;
1462 if (registration_errors) {
1463 ast_test_status_update(test,
1464 "%d test registration error%s occurred. See startup logs for details.\n",
1465 registration_errors, registration_errors > 1 ?
"s" :
"");
1466 return AST_TEST_FAIL;
1469 return AST_TEST_PASS;
1472 static void test_cleanup(
void)
1474 AST_TEST_UNREGISTER(test_registrations);
1476 ao2_cleanup(test_suite_topic);
1477 test_suite_topic = NULL;
1484 #ifdef TEST_FRAMEWORK
1489 if (!test_suite_topic) {
1497 AST_TEST_REGISTER(test_registrations);
Contains all the initialization information required to store a new test definition.
Struct containing info for an AMI event to send out.
pid_t pid
process id of child
size_t errlen
length of buffer holding stderr
char * outbuf
buffer holding stdout
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk main include file. File version handling, generic pbx functions.
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Asterisk version information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Time-related functions and macros.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int exitcode
exit code of child
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
#define ast_strdup(str)
A wrapper for strdup()
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
#define AST_LIST_INSERT_SORTALPHA(head, elm, field, sortfield)
Inserts a list entry into a alphabetically sorted list.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
static void cleanup(void)
Clean up any old apps that we don't need any more.
Asterisk JSON abstraction layer.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Asterisk file paths, configured in asterisk.conf.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
A set of macros to manage forward-linked lists.
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
size_t outlen
length of buffer holding stdout
Support for dynamic strings.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
char * errbuf
buffer holding stderr
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
#define ast_calloc(num, len)
A wrapper for calloc()
Support for logging to various files, console and syslog Configuration in file logger.conf.
Prototypes for public functions only of internal interest,.
A capture of running an external process.
const char * ast_get_version_num(void)
Retrieve the numeric Asterisk version.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
#define AST_TEST_DEFINE(hdr)
Abstract JSON element (object, array, string, int, ...).
Handy terminal functions for vt* terms.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.