00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416732 $");
00035
00036 #include "asterisk/_private.h"
00037
00038 #ifdef TEST_FRAMEWORK
00039 #include "asterisk/test.h"
00040 #include "asterisk/logger.h"
00041 #include "asterisk/linkedlists.h"
00042 #include "asterisk/utils.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/term.h"
00045 #include "asterisk/ast_version.h"
00046 #include "asterisk/paths.h"
00047 #include "asterisk/time.h"
00048 #include "asterisk/manager.h"
00049
00050
00051 static const char * const test_result2str[] = {
00052 [AST_TEST_NOT_RUN] = "NOT RUN",
00053 [AST_TEST_PASS] = "PASS",
00054 [AST_TEST_FAIL] = "FAIL",
00055 };
00056
00057
00058 struct ast_test {
00059 struct ast_test_info info;
00060
00061
00062
00063 struct ast_str *status_str;
00064
00065
00066
00067
00068
00069
00070 struct ast_cli_args *cli;
00071 enum ast_test_result_state state;
00072 unsigned int time;
00073 ast_test_cb_t *cb;
00074 AST_LIST_ENTRY(ast_test) entry;
00075 };
00076
00077
00078 static struct ast_test_execute_results {
00079 unsigned int total_tests;
00080 unsigned int total_passed;
00081 unsigned int total_failed;
00082 unsigned int total_time;
00083 unsigned int last_passed;
00084 unsigned int last_failed;
00085 unsigned int last_time;
00086 } last_results;
00087
00088 enum test_mode {
00089 TEST_ALL = 0,
00090 TEST_CATEGORY = 1,
00091 TEST_NAME_CATEGORY = 2,
00092 };
00093
00094
00095 static AST_LIST_HEAD_STATIC(tests, ast_test);
00096
00097 static struct ast_test *test_alloc(ast_test_cb_t *cb);
00098 static struct ast_test *test_free(struct ast_test *test);
00099 static int test_insert(struct ast_test *test);
00100 static struct ast_test *test_remove(ast_test_cb_t *cb);
00101 static int test_cat_cmp(const char *cat1, const char *cat2);
00102
00103 int __ast_test_status_update(const char *file, const char *func, int line,
00104 struct ast_test *test, const char *fmt, ...)
00105 {
00106 struct ast_str *buf = NULL;
00107 va_list ap;
00108
00109 if (!(buf = ast_str_create(128))) {
00110 return -1;
00111 }
00112
00113 va_start(ap, fmt);
00114 ast_str_set_va(&buf, 0, fmt, ap);
00115 va_end(ap);
00116
00117 if (test->cli) {
00118 ast_cli(test->cli->fd, "[%s:%s:%d]: %s",
00119 file, func, line, ast_str_buffer(buf));
00120 }
00121
00122 ast_str_append(&test->status_str, 0, "[%s:%s:%d]: %s",
00123 file, func, line, ast_str_buffer(buf));
00124
00125 ast_free(buf);
00126
00127 return 0;
00128 }
00129
00130 int ast_test_register(ast_test_cb_t *cb)
00131 {
00132 struct ast_test *test;
00133
00134 if (!cb) {
00135 ast_log(LOG_WARNING, "Attempted to register test without all required information\n");
00136 return -1;
00137 }
00138
00139 if (!(test = test_alloc(cb))) {
00140 return -1;
00141 }
00142
00143 if (test_insert(test)) {
00144 test_free(test);
00145 return -1;
00146 }
00147
00148 return 0;
00149 }
00150
00151 int ast_test_unregister(ast_test_cb_t *cb)
00152 {
00153 struct ast_test *test;
00154
00155 if (!(test = test_remove(cb))) {
00156 return -1;
00157 }
00158
00159 test_free(test);
00160
00161 return 0;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171 static void test_execute(struct ast_test *test)
00172 {
00173 struct timeval begin;
00174
00175 ast_str_reset(test->status_str);
00176
00177 begin = ast_tvnow();
00178 test->state = test->cb(&test->info, TEST_EXECUTE, test);
00179 test->time = ast_tvdiff_ms(ast_tvnow(), begin);
00180 }
00181
00182 static void test_xml_entry(struct ast_test *test, FILE *f)
00183 {
00184 if (!f || !test || test->state == AST_TEST_NOT_RUN) {
00185 return;
00186 }
00187
00188 fprintf(f, "\t<testcase time=\"%u.%u\" name=\"%s%s\"%s>\n",
00189 test->time / 1000, test->time % 1000,
00190 test->info.category, test->info.name,
00191 test->state == AST_TEST_PASS ? "/" : "");
00192
00193 if (test->state == AST_TEST_FAIL) {
00194 fprintf(f, "\t\t<failure><![CDATA[\n%s\n\t\t]]></failure>\n",
00195 S_OR(ast_str_buffer(test->status_str), "NA"));
00196 fprintf(f, "\t</testcase>\n");
00197 }
00198
00199 }
00200
00201 static void test_txt_entry(struct ast_test *test, FILE *f)
00202 {
00203 if (!f || !test) {
00204 return;
00205 }
00206
00207 fprintf(f, "\nName: %s\n", test->info.name);
00208 fprintf(f, "Category: %s\n", test->info.category);
00209 fprintf(f, "Summary: %s\n", test->info.summary);
00210 fprintf(f, "Description: %s\n", test->info.description);
00211 fprintf(f, "Result: %s\n", test_result2str[test->state]);
00212 if (test->state != AST_TEST_NOT_RUN) {
00213 fprintf(f, "Time: %u\n", test->time);
00214 }
00215 if (test->state == AST_TEST_FAIL) {
00216 fprintf(f, "Error Description: %s\n\n", S_OR(ast_str_buffer(test->status_str), "NA"));
00217 }
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 static int test_execute_multiple(const char *name, const char *category, struct ast_cli_args *cli)
00236 {
00237 char result_buf[32] = { 0 };
00238 struct ast_test *test = NULL;
00239 enum test_mode mode = TEST_ALL;
00240 int execute = 0;
00241 int res = 0;
00242
00243 if (!ast_strlen_zero(category)) {
00244 if (!ast_strlen_zero(name)) {
00245 mode = TEST_NAME_CATEGORY;
00246 } else {
00247 mode = TEST_CATEGORY;
00248 }
00249 }
00250
00251 AST_LIST_LOCK(&tests);
00252
00253 memset(&last_results, 0, sizeof(last_results));
00254 AST_LIST_TRAVERSE(&tests, test, entry) {
00255
00256 execute = 0;
00257 switch (mode) {
00258 case TEST_CATEGORY:
00259 if (!test_cat_cmp(test->info.category, category)) {
00260 execute = 1;
00261 }
00262 break;
00263 case TEST_NAME_CATEGORY:
00264 if (!(test_cat_cmp(test->info.category, category)) && !(strcmp(test->info.name, name))) {
00265 execute = 1;
00266 }
00267 break;
00268 case TEST_ALL:
00269 execute = 1;
00270 }
00271
00272 if (execute) {
00273 if (cli) {
00274 ast_cli(cli->fd, "START %s - %s \n", test->info.category, test->info.name);
00275 }
00276
00277
00278 test->cli = cli;
00279
00280
00281 test_execute(test);
00282
00283 test->cli = NULL;
00284
00285
00286 last_results.last_time += test->time;
00287 if (test->state == AST_TEST_PASS) {
00288 last_results.last_passed++;
00289 } else if (test->state == AST_TEST_FAIL) {
00290 last_results.last_failed++;
00291 }
00292
00293 if (cli) {
00294 term_color(result_buf,
00295 test_result2str[test->state],
00296 (test->state == AST_TEST_FAIL) ? COLOR_RED : COLOR_GREEN,
00297 0,
00298 sizeof(result_buf));
00299 ast_cli(cli->fd, "END %s - %s Time: %s%ums Result: %s\n",
00300 test->info.category,
00301 test->info.name,
00302 test->time ? "" : "<",
00303 test->time ? test->time : 1,
00304 result_buf);
00305 }
00306 }
00307
00308
00309
00310 last_results.total_time += test->time;
00311 last_results.total_tests++;
00312 if (test->state != AST_TEST_NOT_RUN) {
00313 if (test->state == AST_TEST_PASS) {
00314 last_results.total_passed++;
00315 } else {
00316 last_results.total_failed++;
00317 }
00318 }
00319 }
00320 res = last_results.last_passed + last_results.last_failed;
00321 AST_LIST_UNLOCK(&tests);
00322
00323 return res;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 static int test_generate_results(const char *name, const char *category, const char *xml_path, const char *txt_path)
00346 {
00347 enum test_mode mode = TEST_ALL;
00348 FILE *f_xml = NULL, *f_txt = NULL;
00349 int res = 0;
00350 struct ast_test *test = NULL;
00351
00352
00353 if (ast_strlen_zero(xml_path) && ast_strlen_zero(txt_path)) {
00354 return -1;
00355 }
00356
00357
00358 if (!ast_strlen_zero(category)) {
00359 if (!ast_strlen_zero(name)) {
00360 mode = TEST_NAME_CATEGORY;
00361 } else {
00362 mode = TEST_CATEGORY;
00363 }
00364 }
00365
00366 if (!ast_strlen_zero(xml_path)) {
00367 if (!(f_xml = fopen(xml_path, "w"))) {
00368 ast_log(LOG_WARNING, "Could not open file %s for xml test results\n", xml_path);
00369 res = -1;
00370 goto done;
00371 }
00372 }
00373 if (!ast_strlen_zero(txt_path)) {
00374 if (!(f_txt = fopen(txt_path, "w"))) {
00375 ast_log(LOG_WARNING, "Could not open file %s for text output of test results\n", txt_path);
00376 res = -1;
00377 goto done;
00378 }
00379 }
00380
00381 AST_LIST_LOCK(&tests);
00382
00383 if (f_xml) {
00384
00385
00386
00387 fprintf(f_xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00388 fprintf(f_xml, "<testsuite errors=\"0\" time=\"%u.%u\" tests=\"%u\" "
00389 "name=\"AsteriskUnitTests\">\n",
00390 last_results.total_time / 1000, last_results.total_time % 1000,
00391 last_results.total_tests);
00392 fprintf(f_xml, "\t<properties>\n");
00393 fprintf(f_xml, "\t\t<property name=\"version\" value=\"%s\"/>\n", ast_get_version());
00394 fprintf(f_xml, "\t</properties>\n");
00395 }
00396
00397
00398 if (f_txt) {
00399 fprintf(f_txt, "Asterisk Version: %s\n", ast_get_version());
00400 fprintf(f_txt, "Asterisk Version Number: %s\n", ast_get_version_num());
00401 fprintf(f_txt, "Number of Tests: %u\n", last_results.total_tests);
00402 fprintf(f_txt, "Number of Tests Executed: %u\n", (last_results.total_passed + last_results.total_failed));
00403 fprintf(f_txt, "Passed Tests: %u\n", last_results.total_passed);
00404 fprintf(f_txt, "Failed Tests: %u\n", last_results.total_failed);
00405 fprintf(f_txt, "Total Execution Time: %u\n", last_results.total_time);
00406 }
00407
00408
00409 AST_LIST_TRAVERSE(&tests, test, entry) {
00410 switch (mode) {
00411 case TEST_CATEGORY:
00412 if (!test_cat_cmp(test->info.category, category)) {
00413 test_xml_entry(test, f_xml);
00414 test_txt_entry(test, f_txt);
00415 }
00416 break;
00417 case TEST_NAME_CATEGORY:
00418 if (!(strcmp(test->info.category, category)) && !(strcmp(test->info.name, name))) {
00419 test_xml_entry(test, f_xml);
00420 test_txt_entry(test, f_txt);
00421 }
00422 break;
00423 case TEST_ALL:
00424 test_xml_entry(test, f_xml);
00425 test_txt_entry(test, f_txt);
00426 }
00427 }
00428 AST_LIST_UNLOCK(&tests);
00429
00430 done:
00431 if (f_xml) {
00432 fprintf(f_xml, "</testsuite>\n");
00433 fclose(f_xml);
00434 }
00435 if (f_txt) {
00436 fclose(f_txt);
00437 }
00438
00439 return res;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449 static int test_insert(struct ast_test *test)
00450 {
00451
00452
00453
00454
00455 AST_LIST_LOCK(&tests);
00456 AST_LIST_INSERT_SORTALPHA(&tests, test, entry, info.category);
00457 AST_LIST_UNLOCK(&tests);
00458
00459 return 0;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468 static struct ast_test *test_remove(ast_test_cb_t *cb)
00469 {
00470 struct ast_test *cur = NULL;
00471
00472 AST_LIST_LOCK(&tests);
00473 AST_LIST_TRAVERSE_SAFE_BEGIN(&tests, cur, entry) {
00474 if (cur->cb == cb) {
00475 AST_LIST_REMOVE_CURRENT(entry);
00476 break;
00477 }
00478 }
00479 AST_LIST_TRAVERSE_SAFE_END;
00480 AST_LIST_UNLOCK(&tests);
00481
00482 return cur;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static int test_cat_cmp(const char *cat1, const char *cat2)
00494 {
00495 int len1 = 0;
00496 int len2 = 0;
00497
00498 if (!cat1 || !cat2) {
00499 return -1;
00500 }
00501
00502 len1 = strlen(cat1);
00503 len2 = strlen(cat2);
00504
00505 if (len2 > len1) {
00506 return -1;
00507 }
00508
00509 return strncmp(cat1, cat2, len2) ? 1 : 0;
00510 }
00511
00512
00513
00514
00515
00516 static struct ast_test *test_free(struct ast_test *test)
00517 {
00518 if (!test) {
00519 return NULL;
00520 }
00521
00522 ast_free(test->status_str);
00523 ast_free(test);
00524
00525 return NULL;
00526 }
00527
00528
00529
00530
00531
00532 static struct ast_test *test_alloc(ast_test_cb_t *cb)
00533 {
00534 struct ast_test *test;
00535
00536 if (!cb || !(test = ast_calloc(1, sizeof(*test)))) {
00537 return NULL;
00538 }
00539
00540 test->cb = cb;
00541
00542 test->cb(&test->info, TEST_INIT, test);
00543
00544 if (ast_strlen_zero(test->info.name)) {
00545 ast_log(LOG_WARNING, "Test has no name, test registration refused.\n");
00546 return test_free(test);
00547 }
00548
00549 if (ast_strlen_zero(test->info.category)) {
00550 ast_log(LOG_WARNING, "Test %s has no category, test registration refused.\n",
00551 test->info.name);
00552 return test_free(test);
00553 }
00554
00555 if (test->info.category[0] != '/' || test->info.category[strlen(test->info.category) - 1] != '/') {
00556 ast_log(LOG_WARNING, "Test category is missing a leading or trailing backslash for test %s%s\n",
00557 test->info.category, test->info.name);
00558 }
00559
00560 if (ast_strlen_zero(test->info.summary)) {
00561 ast_log(LOG_WARNING, "Test %s/%s has no summary, test registration refused.\n",
00562 test->info.category, test->info.name);
00563 return test_free(test);
00564 }
00565
00566 if (ast_strlen_zero(test->info.description)) {
00567 ast_log(LOG_WARNING, "Test %s/%s has no description, test registration refused.\n",
00568 test->info.category, test->info.name);
00569 return test_free(test);
00570 }
00571
00572 if (!(test->status_str = ast_str_create(128))) {
00573 return test_free(test);
00574 }
00575
00576 return test;
00577 }
00578
00579 static char *complete_test_category(const char *line, const char *word, int pos, int state)
00580 {
00581 int which = 0;
00582 int wordlen = strlen(word);
00583 char *ret = NULL;
00584 struct ast_test *test;
00585
00586 AST_LIST_LOCK(&tests);
00587 AST_LIST_TRAVERSE(&tests, test, entry) {
00588 if (!strncasecmp(word, test->info.category, wordlen) && ++which > state) {
00589 ret = ast_strdup(test->info.category);
00590 break;
00591 }
00592 }
00593 AST_LIST_UNLOCK(&tests);
00594 return ret;
00595 }
00596
00597 static char *complete_test_name(const char *line, const char *word, int pos, int state, const char *category)
00598 {
00599 int which = 0;
00600 int wordlen = strlen(word);
00601 char *ret = NULL;
00602 struct ast_test *test;
00603
00604 AST_LIST_LOCK(&tests);
00605 AST_LIST_TRAVERSE(&tests, test, entry) {
00606 if (!test_cat_cmp(test->info.category, category) && (!strncasecmp(word, test->info.name, wordlen) && ++which > state)) {
00607 ret = ast_strdup(test->info.name);
00608 break;
00609 }
00610 }
00611 AST_LIST_UNLOCK(&tests);
00612 return ret;
00613 }
00614
00615
00616 static char *test_cli_show_registered(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00617 {
00618 #define FORMAT "%-25.25s %-30.30s %-40.40s %-13.13s\n"
00619 static const char * const option1[] = { "all", "category", NULL };
00620 static const char * const option2[] = { "name", NULL };
00621 struct ast_test *test = NULL;
00622 int count = 0;
00623 switch (cmd) {
00624 case CLI_INIT:
00625 e->command = "test show registered";
00626
00627 e->usage =
00628 "Usage: 'test show registered' can be used in three ways.\n"
00629 " 1. 'test show registered all' shows all registered tests\n"
00630 " 2. 'test show registered category [test category]' shows all tests in the given\n"
00631 " category.\n"
00632 " 3. 'test show registered category [test category] name [test name]' shows all\n"
00633 " tests in a given category matching a given name\n";
00634 return NULL;
00635 case CLI_GENERATE:
00636 if (a->pos == 3) {
00637 return ast_cli_complete(a->word, option1, a->n);
00638 }
00639 if (a->pos == 4) {
00640 return complete_test_category(a->line, a->word, a->pos, a->n);
00641 }
00642 if (a->pos == 5) {
00643 return ast_cli_complete(a->word, option2, a->n);
00644 }
00645 if (a->pos == 6) {
00646 return complete_test_name(a->line, a->word, a->pos, a->n, a->argv[3]);
00647 }
00648 return NULL;
00649 case CLI_HANDLER:
00650 if ((a->argc < 4) || (a->argc == 6) || (a->argc > 7) ||
00651 ((a->argc == 4) && strcmp(a->argv[3], "all")) ||
00652 ((a->argc == 7) && strcmp(a->argv[5], "name"))) {
00653 return CLI_SHOWUSAGE;
00654 }
00655 ast_cli(a->fd, FORMAT, "Category", "Name", "Summary", "Test Result");
00656 ast_cli(a->fd, FORMAT, "--------", "----", "-------", "-----------");
00657 AST_LIST_LOCK(&tests);
00658 AST_LIST_TRAVERSE(&tests, test, entry) {
00659 if ((a->argc == 4) ||
00660 ((a->argc == 5) && !test_cat_cmp(test->info.category, a->argv[4])) ||
00661 ((a->argc == 7) && !strcmp(test->info.category, a->argv[4]) && !strcmp(test->info.name, a->argv[6]))) {
00662
00663 ast_cli(a->fd, FORMAT, test->info.category, test->info.name,
00664 test->info.summary, test_result2str[test->state]);
00665 count++;
00666 }
00667 }
00668 AST_LIST_UNLOCK(&tests);
00669 ast_cli(a->fd, FORMAT, "--------", "----", "-------", "-----------");
00670 ast_cli(a->fd, "\n%d Registered Tests Matched\n", count);
00671 default:
00672 return NULL;
00673 }
00674
00675 return CLI_SUCCESS;
00676 }
00677
00678 static char *test_cli_execute_registered(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00679 {
00680 static const char * const option1[] = { "all", "category", NULL };
00681 static const char * const option2[] = { "name", NULL };
00682
00683 switch (cmd) {
00684 case CLI_INIT:
00685 e->command = "test execute";
00686 e->usage =
00687 "Usage: test execute can be used in three ways.\n"
00688 " 1. 'test execute all' runs all registered tests\n"
00689 " 2. 'test execute category [test category]' runs all tests in the given\n"
00690 " category.\n"
00691 " 3. 'test execute category [test category] name [test name]' runs all\n"
00692 " tests in a given category matching a given name\n";
00693 return NULL;
00694 case CLI_GENERATE:
00695 if (a->pos == 2) {
00696 return ast_cli_complete(a->word, option1, a->n);
00697 }
00698 if (a->pos == 3) {
00699 return complete_test_category(a->line, a->word, a->pos, a->n);
00700 }
00701 if (a->pos == 4) {
00702 return ast_cli_complete(a->word, option2, a->n);
00703 }
00704 if (a->pos == 5) {
00705 return complete_test_name(a->line, a->word, a->pos, a->n, a->argv[3]);
00706 }
00707 return NULL;
00708 case CLI_HANDLER:
00709
00710 if (a->argc < 3|| a->argc > 6) {
00711 return CLI_SHOWUSAGE;
00712 }
00713
00714 if ((a->argc == 3) && !strcmp(a->argv[2], "all")) {
00715 ast_cli(a->fd, "Running all available tests...\n\n");
00716 test_execute_multiple(NULL, NULL, a);
00717 } else if (a->argc == 4) {
00718 ast_cli(a->fd, "Running all available tests matching category %s\n\n", a->argv[3]);
00719 test_execute_multiple(NULL, a->argv[3], a);
00720 } else if (a->argc == 6) {
00721 ast_cli(a->fd, "Running all available tests matching category %s and name %s\n\n", a->argv[3], a->argv[5]);
00722 test_execute_multiple(a->argv[5], a->argv[3], a);
00723 } else {
00724 return CLI_SHOWUSAGE;
00725 }
00726
00727 AST_LIST_LOCK(&tests);
00728 if (!(last_results.last_passed + last_results.last_failed)) {
00729 ast_cli(a->fd, "--- No Tests Found! ---\n");
00730 }
00731 ast_cli(a->fd, "\n%u Test(s) Executed %u Passed %u Failed\n",
00732 (last_results.last_passed + last_results.last_failed),
00733 last_results.last_passed,
00734 last_results.last_failed);
00735 AST_LIST_UNLOCK(&tests);
00736 default:
00737 return NULL;
00738 }
00739
00740 return CLI_SUCCESS;
00741 }
00742
00743 static char *test_cli_show_results(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00744 {
00745 #define FORMAT_RES_ALL1 "%s%s %-30.30s %-25.25s %-10.10s\n"
00746 #define FORMAT_RES_ALL2 "%s%s %-30.30s %-25.25s %s%ums\n"
00747 static const char * const option1[] = { "all", "failed", "passed", NULL };
00748 char result_buf[32] = { 0 };
00749 struct ast_test *test = NULL;
00750 int failed = 0;
00751 int passed = 0;
00752 int mode;
00753
00754 switch (cmd) {
00755 case CLI_INIT:
00756 e->command = "test show results";
00757 e->usage =
00758 "Usage: test show results can be used in three ways\n"
00759 " 1. 'test show results all' Displays results for all executed tests.\n"
00760 " 2. 'test show results passed' Displays results for all passed tests.\n"
00761 " 3. 'test show results failed' Displays results for all failed tests.\n";
00762 return NULL;
00763 case CLI_GENERATE:
00764 if (a->pos == 3) {
00765 return ast_cli_complete(a->word, option1, a->n);
00766 }
00767 return NULL;
00768 case CLI_HANDLER:
00769
00770
00771 if (a->argc != 4) {
00772 return CLI_SHOWUSAGE;
00773 } else if (!strcmp(a->argv[3], "passed")) {
00774 mode = 2;
00775 } else if (!strcmp(a->argv[3], "failed")) {
00776 mode = 1;
00777 } else if (!strcmp(a->argv[3], "all")) {
00778 mode = 0;
00779 } else {
00780 return CLI_SHOWUSAGE;
00781 }
00782
00783 ast_cli(a->fd, FORMAT_RES_ALL1, "Result", "", "Name", "Category", "Time");
00784 AST_LIST_LOCK(&tests);
00785 AST_LIST_TRAVERSE(&tests, test, entry) {
00786 if (test->state == AST_TEST_NOT_RUN) {
00787 continue;
00788 }
00789 test->state == AST_TEST_FAIL ? failed++ : passed++;
00790 if (!mode || ((mode == 1) && (test->state == AST_TEST_FAIL)) || ((mode == 2) && (test->state == AST_TEST_PASS))) {
00791
00792 term_color(result_buf, test_result2str[test->state],
00793 (test->state == AST_TEST_FAIL) ? COLOR_RED : COLOR_GREEN,
00794 0, sizeof(result_buf));
00795
00796 ast_cli(a->fd, FORMAT_RES_ALL2,
00797 result_buf,
00798 " ",
00799 test->info.name,
00800 test->info.category,
00801 test->time ? " " : "<",
00802 test->time ? test->time : 1);
00803 }
00804 }
00805 AST_LIST_UNLOCK(&tests);
00806
00807 ast_cli(a->fd, "%d Test(s) Executed %d Passed %d Failed\n", (failed + passed), passed, failed);
00808 default:
00809 return NULL;
00810 }
00811 return CLI_SUCCESS;
00812 }
00813
00814 static char *test_cli_generate_results(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00815 {
00816 static const char * const option[] = { "xml", "txt", NULL };
00817 const char *file = NULL;
00818 const char *type = "";
00819 int isxml = 0;
00820 int res = 0;
00821 struct ast_str *buf = NULL;
00822 struct timeval time = ast_tvnow();
00823
00824 switch (cmd) {
00825 case CLI_INIT:
00826 e->command = "test generate results";
00827 e->usage =
00828 "Usage: 'test generate results'\n"
00829 " Generates test results in either xml or txt format. An optional \n"
00830 " file path may be provided to specify the location of the xml or\n"
00831 " txt file\n"
00832 " \nExample usage:\n"
00833 " 'test generate results xml' this writes to a default file\n"
00834 " 'test generate results xml /path/to/file.xml' writes to specified file\n";
00835 return NULL;
00836 case CLI_GENERATE:
00837 if (a->pos == 3) {
00838 return ast_cli_complete(a->word, option, a->n);
00839 }
00840 return NULL;
00841 case CLI_HANDLER:
00842
00843
00844 if (a->argc < 4 || a->argc > 5) {
00845 return CLI_SHOWUSAGE;
00846 } else if (!strcmp(a->argv[3], "xml")) {
00847 type = "xml";
00848 isxml = 1;
00849 } else if (!strcmp(a->argv[3], "txt")) {
00850 type = "txt";
00851 } else {
00852 return CLI_SHOWUSAGE;
00853 }
00854
00855 if (a->argc == 5) {
00856 file = a->argv[4];
00857 } else {
00858 if (!(buf = ast_str_create(256))) {
00859 return NULL;
00860 }
00861 ast_str_set(&buf, 0, "%s/asterisk_test_results-%ld.%s", ast_config_AST_LOG_DIR, (long) time.tv_sec, type);
00862
00863 file = ast_str_buffer(buf);
00864 }
00865
00866 if (isxml) {
00867 res = test_generate_results(NULL, NULL, file, NULL);
00868 } else {
00869 res = test_generate_results(NULL, NULL, NULL, file);
00870 }
00871
00872 if (!res) {
00873 ast_cli(a->fd, "Results Generated Successfully: %s\n", S_OR(file, ""));
00874 } else {
00875 ast_cli(a->fd, "Results Could Not Be Generated: %s\n", S_OR(file, ""));
00876 }
00877
00878 ast_free(buf);
00879 default:
00880 return NULL;
00881 }
00882
00883 return CLI_SUCCESS;
00884 }
00885
00886 static struct ast_cli_entry test_cli[] = {
00887 AST_CLI_DEFINE(test_cli_show_registered, "show registered tests"),
00888 AST_CLI_DEFINE(test_cli_execute_registered, "execute registered tests"),
00889 AST_CLI_DEFINE(test_cli_show_results, "show last test results"),
00890 AST_CLI_DEFINE(test_cli_generate_results, "generate test results to file"),
00891 };
00892
00893 int __ast_test_suite_event_notify(const char *file, const char *func, int line,
00894 const char *state, const char *fmt, ...)
00895 {
00896 struct ast_str *buf = NULL;
00897 va_list ap;
00898
00899 if (!(buf = ast_str_create(128))) {
00900 return -1;
00901 }
00902
00903 va_start(ap, fmt);
00904 ast_str_set_va(&buf, 0, fmt, ap);
00905 va_end(ap);
00906
00907 manager_event(EVENT_FLAG_TEST, "TestEvent",
00908 "Type: StateChange\r\n"
00909 "State: %s\r\n"
00910 "AppFile: %s\r\n"
00911 "AppFunction: %s\r\n"
00912 "AppLine: %d\r\n%s\r\n",
00913 state, file, func, line, ast_str_buffer(buf));
00914
00915 ast_free(buf);
00916
00917 return 0;
00918 }
00919
00920 int __ast_test_suite_assert_notify(const char *file, const char *func, int line,
00921 const char *exp)
00922 {
00923 manager_event(EVENT_FLAG_TEST, "TestEvent",
00924 "Type: Assert\r\n"
00925 "AppFile: %s\r\n"
00926 "AppFunction: %s\r\n"
00927 "AppLine: %d\r\n"
00928 "Expression: %s\r\n",
00929 file, func, line, exp);
00930
00931 return 0;
00932 }
00933
00934 static void test_shutdown(void)
00935 {
00936 ast_cli_unregister_multiple(test_cli, ARRAY_LEN(test_cli));
00937 }
00938
00939 #endif
00940
00941 int ast_test_init()
00942 {
00943 #ifdef TEST_FRAMEWORK
00944
00945 ast_cli_register_multiple(test_cli, ARRAY_LEN(test_cli));
00946 ast_register_atexit(test_shutdown);
00947 #endif
00948
00949 return 0;
00950 }