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