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