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