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 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <getopt.h>
00029 #include <errno.h>
00030 #include <string.h>
00031 #include <fcntl.h>
00032 #include <unistd.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <libxml/parser.h>
00036 #include <libxml/tree.h>
00037 #include <signal.h>
00038 #include <ctype.h>
00039
00040 #include "testrunnerlite.h"
00041 #include "testdefinitionparser.h"
00042 #include "testresultlogger.h"
00043 #include "testfilters.h"
00044 #include "executor.h"
00045 #include "remote_executor.h"
00046 #include "manual_executor.h"
00047 #include "utils.h"
00048 #include "log.h"
00049
00050
00051
00052
00053
00054
00055
00056 extern char* optarg;
00057
00058
00059
00060
00061
00062
00063
00064 struct timeval created;
00065 testrunner_lite_options opts;
00066 char *global_failure = NULL;
00067 int bail_out = 0;
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 LOCAL td_td *current_td = NULL;
00079 LOCAL td_suite *current_suite = NULL;
00080 LOCAL td_set *current_set = NULL;
00081 LOCAL xmlChar *cur_case_name = BAD_CAST"";
00082 LOCAL int cur_step_num;
00083
00084 LOCAL int passcount = 0;
00085 LOCAL int failcount = 0;
00086 LOCAL int casecount = 0;
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 LOCAL void process_td(td_td *);
00099
00100 LOCAL void end_td();
00101
00102 LOCAL void process_hwiddetect();
00103
00104 LOCAL void process_suite(td_suite *);
00105
00106 LOCAL void process_set(td_set *);
00107
00108 LOCAL int process_case (const void *, const void *);
00109
00110 LOCAL int case_result_fail (const void *, const void *);
00111
00112 LOCAL int process_get (const void *, const void *);
00113
00114 LOCAL int step_execute (const void *, const void *);
00115
00116 LOCAL int prepost_steps_execute (const void *, const void *);
00117
00118 LOCAL int step_result_na (const void *, const void *);
00119
00120 LOCAL int step_post_process (const void *, const void *);
00121
00122
00123
00124
00125
00126
00127
00133 LOCAL int step_execute (const void *data, const void *user)
00134 {
00135 int res = CASE_PASS;
00136 td_step *step = (td_step *)data;
00137 td_case *c = (td_case *)user;
00138 exec_data edata;
00139
00140 cur_step_num++;
00141
00142 memset (&edata, 0x0, sizeof (exec_data));
00143 if (bail_out) {
00144 res = CASE_FAIL;
00145 step->has_result = 1;
00146 step->return_code = bail_out;
00147 if (global_failure) {
00148 step->failure_info = xmlCharStrdup (global_failure);
00149 c->failure_info = xmlCharStrdup (global_failure);
00150 }
00151 goto out;
00152 }
00153
00154 if (step->manual) {
00155 if (c->dummy) {
00156 LOG_MSG (LOG_WARNING,
00157 "manual pre/post steps not supported");
00158 goto out;
00159 }
00160 if (!c->gen.manual)
00161 LOG_MSG (LOG_WARNING, "Executing manual step from "
00162 "automatic case %s "
00163 "(generally not a good idea)",
00164 c->gen.name);
00165 res = execute_manual (step);
00166 goto out;
00167 }
00168
00169 init_exec_data(&edata);
00170
00171 edata.redirect_output = REDIRECT_OUTPUT;
00172 edata.soft_timeout = c->gen.timeout;
00173 edata.hard_timeout = COMMON_HARD_TIMEOUT;
00174
00175 if (step->step) {
00176 execute((char*)step->step, &edata);
00177
00178 if (step->stdout_) free (step->stdout_);
00179 if (step->stderr_) free (step->stderr_);
00180 if (step->failure_info) free (step->failure_info);
00181
00182 if (edata.stdout_data.buffer) {
00183 step->stdout_ = edata.stdout_data.buffer;
00184 }
00185 if (edata.stderr_data.buffer) {
00186 step->stderr_ = edata.stderr_data.buffer;
00187 }
00188 if (edata.failure_info.buffer) {
00189 step->failure_info = edata.failure_info.buffer;
00190 c->failure_info = xmlCharStrdup ((char *)
00191 step->failure_info);
00192
00193 LOG_MSG (LOG_INFO, "FAILURE INFO: %s",
00194 step->failure_info);
00195 }
00196
00197 step->pgid = edata.pgid;
00198 step->pid = edata.pid;
00199 step->has_result = 1;
00200 step->return_code = edata.result;
00201 step->start = edata.start_time;
00202 step->end = edata.end_time;
00203
00204
00205
00206
00207 if (c->dummy) {
00208 if (step->has_expected_result &&
00209 (step->return_code != step->expected_result)) {
00210 LOG_MSG (LOG_INFO,
00211 "STEP: %s return %d expected %d\n",
00212 step->step, step->return_code,
00213 step->expected_result);
00214 res = CASE_FAIL;
00215 }
00216 } else if (step->return_code != step->expected_result) {
00217 LOG_MSG (LOG_INFO, "STEP: %s return %d expected %d\n",
00218 step->step, step->return_code,
00219 step->expected_result);
00220 res = CASE_FAIL;
00221 }
00222 }
00223 out:
00224 if (res != CASE_PASS)
00225 c->case_res = res;
00226
00227
00228 return (res == CASE_PASS);
00229 }
00230
00231
00237 LOCAL int prepost_steps_execute (const void *data, const void *user)
00238 {
00239 td_steps *steps = (td_steps *)data;
00240 td_case *dummy = (td_case *)user;
00241
00242 dummy->gen.timeout = steps->timeout;
00243
00244 if (xmlListSize(steps->steps) > 0) {
00245 xmlListWalk (steps->steps, step_execute, dummy);
00246 }
00247
00248 return 1;
00249 }
00250
00251
00257 LOCAL int step_result_na (const void *data, const void *user)
00258 {
00259 td_step *step = (td_step *)data;
00260 char *failure_info = (char *)user;
00261
00262 step->has_result = 1;
00263 step->return_code = step->expected_result + 255;
00264 step->failure_info = xmlCharStrdup (failure_info);
00265
00266 return 1;
00267 }
00268
00269
00276 LOCAL int step_post_process (const void *data, const void *user)
00277 {
00278 td_step *step = (td_step *)data;
00279 td_case *c = (td_case *)user;
00280
00281
00282 if (step->manual)
00283 goto out;
00284
00285 if (c->filtered)
00286 goto out;
00287
00288
00289 if (!step->start)
00290 goto out;
00291
00292
00293 if (!step->pgid)
00294 goto out;
00295
00296 if (opts.target_address) {
00297 ssh_kill (opts.target_address, step->pid);
00298 }
00299 kill_pgroup(step->pgid, SIGKILL);
00300
00301 out:
00302 return 1;
00303 }
00304
00305
00311 LOCAL int process_case (const void *data, const void *user)
00312 {
00313
00314 td_case *c = (td_case *)data;
00315
00316 if (c->gen.manual && !opts.run_manual) {
00317 LOG_MSG(LOG_DEBUG, "Skipping manual case %s",
00318 c->gen.name);
00319 c->filtered = 1;
00320 return 1;
00321 }
00322 if (!c->gen.manual && !opts.run_automatic) {
00323 LOG_MSG(LOG_DEBUG, "Skipping automatic case %s",
00324 c->gen.name);
00325 c->filtered = 1;
00326 return 1;
00327 }
00328 if (filter_case (c)) {
00329 LOG_MSG (LOG_INFO, "Test case %s is filtered", c->gen.name);
00330 return 1;
00331 }
00332 if (c->state && !xmlStrcmp (c->state, BAD_CAST "Design")) {
00333 LOG_MSG (LOG_INFO, "Skipping case in Design state (%s)",
00334 c->gen.name);
00335 c->case_res = CASE_NA;
00336 return 1;
00337 }
00338
00339 cur_case_name = c->gen.name;
00340 LOG_MSG (LOG_INFO, "Starting test case %s", c->gen.name);
00341 casecount++;
00342
00343 c->case_res = CASE_PASS;
00344 if (c->gen.timeout == 0)
00345 c->gen.timeout = COMMON_SOFT_TIMEOUT;
00346
00347 if (c->gen.manual && opts.run_manual)
00348 pre_manual (c);
00349 if (xmlListSize (c->steps) == 0) {
00350 LOG_MSG (LOG_WARNING, "Case with no steps (%s).",
00351 c->gen.name);
00352 c->case_res = CASE_NA;
00353 }
00354 cur_step_num = 0;
00355
00356 xmlListWalk (c->steps, step_execute, data);
00357 xmlListWalk (c->steps, step_post_process, data);
00358
00359 if (c->gen.manual && opts.run_manual)
00360 post_manual (c);
00361
00362 LOG_MSG (LOG_INFO, "Finished test case %s Result: %s",
00363 c->gen.name, case_result_str(c->case_res));
00364 passcount += (c->case_res == CASE_PASS);
00365 failcount += (c->case_res == CASE_FAIL);
00366 return 1;
00367 }
00368
00374 LOCAL int case_result_fail (const void *data, const void *user)
00375 {
00376
00377 td_case *c = (td_case *)data;
00378 char *failure_info = (char *)user;
00379
00380 LOG_MSG (LOG_DEBUG, "Setting FAIL result for case %s", c->gen.name);
00381
00382 c->case_res = CASE_FAIL;
00383 c->failure_info = xmlCharStrdup (failure_info);
00384
00385 xmlListWalk (c->steps, step_result_na, user);
00386
00387 return 1;
00388 }
00389
00390
00396 LOCAL int process_get (const void *data, const void *user)
00397 {
00398
00399 td_file *file = (td_file *)data;
00400 xmlChar *command;
00401 char *fname;
00402 exec_data edata;
00403 char *remote = opts.target_address;
00404
00405 memset (&edata, 0x0, sizeof (exec_data));
00406 init_exec_data(&edata);
00407 edata.soft_timeout = COMMON_SOFT_TIMEOUT;
00408 edata.hard_timeout = COMMON_HARD_TIMEOUT;
00409
00410 fname = malloc (strlen((char *)file->filename) + 1);
00411 trim_string ((char *)file->filename, fname);
00412
00413
00414
00415
00416 if (remote) {
00417 opts.target_address = NULL;
00418 command = (xmlChar *)malloc (strlen ("scp ") +
00419 strlen (fname) +
00420 strlen (opts.output_folder) +
00421 strlen (remote) + 10);
00422 sprintf ((char *)command, "scp %s:\'%s\' %s", remote, fname,
00423 opts.output_folder);
00424
00425 } else {
00426 command = (xmlChar *)malloc (strlen ("cp ") +
00427 strlen (fname) +
00428 strlen (opts.output_folder) + 2);
00429 sprintf ((char *)command, "cp %s %s", fname,
00430 opts.output_folder);
00431 }
00432 LOG_MSG (LOG_DEBUG, "%s: Executing command: %s", PROGNAME,
00433 (char*)command);
00434
00435
00436
00437 execute((char*)command, &edata);
00438
00439 if (edata.result) {
00440 LOG_MSG (LOG_INFO, "%s: %s failed: %s\n", PROGNAME, command,
00441 (char *)(edata.stderr_data.buffer ?
00442 edata.stderr_data.buffer :
00443 BAD_CAST "no info available"));
00444 }
00445 opts.target_address = remote;
00446 if (edata.stdout_data.buffer) free (edata.stdout_data.buffer);
00447 if (edata.stderr_data.buffer) free (edata.stderr_data.buffer);
00448 if (edata.failure_info.buffer) free (edata.failure_info.buffer);
00449
00450 if (!file->delete_after)
00451 goto out;
00452
00453 memset (&edata, 0x0, sizeof (exec_data));
00454 init_exec_data(&edata);
00455 edata.soft_timeout = COMMON_SOFT_TIMEOUT;
00456 edata.hard_timeout = COMMON_HARD_TIMEOUT;
00457 sprintf ((char *)command, "rm -f %s", fname);
00458 LOG_MSG (LOG_DEBUG, "%s: Executing command: %s", PROGNAME,
00459 (char*)command);
00460 execute((char*)command, &edata);
00461 if (edata.result) {
00462 LOG_MSG (LOG_WARNING, "%s: %s failed: %s\n", PROGNAME, command,
00463 (char *)(edata.stderr_data.buffer ?
00464 edata.stderr_data.buffer :
00465 BAD_CAST "no info available"));
00466 }
00467 if (edata.stdout_data.buffer) free (edata.stdout_data.buffer);
00468 if (edata.stderr_data.buffer) free (edata.stderr_data.buffer);
00469 if (edata.failure_info.buffer) free (edata.failure_info.buffer);
00470
00471 out:
00472 free (command);
00473 free (fname);
00474 return 1;
00475 }
00476
00480 LOCAL void process_td (td_td *td)
00481 {
00482 current_td = td;
00483 write_td_start (td);
00484 }
00485
00488 LOCAL void end_td ()
00489 {
00490 write_td_end (current_td);
00491 td_td_delete (current_td);
00492 current_td = NULL;
00493 }
00494
00497 LOCAL void process_hwiddetect ()
00498 {
00499 exec_data edata;
00500 char* trimmed = NULL;
00501 size_t length = 0;
00502
00503 if (current_td && current_td->hw_detector) {
00504 init_exec_data(&edata);
00505 edata.redirect_output = REDIRECT_OUTPUT;
00506 edata.soft_timeout = COMMON_SOFT_TIMEOUT;
00507 edata.hard_timeout = COMMON_HARD_TIMEOUT;
00508
00509 execute((char*)current_td->hw_detector, &edata);
00510
00511 if (edata.result != EXIT_SUCCESS) {
00512 LOG_MSG (LOG_WARNING, "Running HW ID detector "
00513 "failed with return value %d",
00514 edata.result);
00515 } else if (edata.stdout_data.buffer) {
00516
00517 length = strlen((char*)edata.stdout_data.buffer);
00518 trimmed = (char*)malloc(length + 1);
00519 trim_string((char*)edata.stdout_data.buffer, trimmed);
00520
00521 current_td->detected_hw = xmlCharStrdup(trimmed);
00522 LOG_MSG (LOG_INFO, "Detected HW ID '%s'",
00523 current_td->detected_hw);
00524 }
00525
00526 clean_exec_data(&edata);
00527 }
00528
00529 free(trimmed);
00530 }
00531
00535 LOCAL void process_suite (td_suite *s)
00536 {
00537 LOG_MSG (LOG_INFO, "Test suite: %s", s->gen.name);
00538
00539 write_pre_suite (s);
00540 current_suite = s;
00541
00542 }
00543
00546 LOCAL void end_suite ()
00547 {
00548 write_post_suite (current_suite);
00549 td_suite_delete (current_suite);
00550 current_suite = NULL;
00551 }
00552
00556 LOCAL void process_set (td_set *s)
00557 {
00558 td_case dummy;
00559
00560
00561
00562
00563 if (filter_set (s)) {
00564 LOG_MSG (LOG_INFO, "Test set %s is filtered", s->gen.name);
00565 goto skip_all;
00566 }
00567
00568
00569
00570
00571 if (s->gen.hwid && current_td->detected_hw &&
00572 list_contains((const char *)s->gen.hwid,
00573 (const char *) current_td->detected_hw, ",") == 0) {
00574 LOG_MSG (LOG_INFO, "Test set %s is filtered based on HW ID",
00575 s->gen.name);
00576 goto skip_all;
00577 }
00578
00579
00580
00581
00582 s->environment = xmlCharStrdup (opts.environment);
00583 if (!xmlListSearch (s->environments, opts.environment)) {
00584 LOG_MSG (LOG_INFO, "Test set %s not run on "
00585 "environment: %s",
00586 s->gen.name, opts.environment);
00587 goto skip_all;
00588 }
00589 current_set = s;
00590 LOG_MSG (LOG_INFO, "Test set: %s", s->gen.name);
00591 write_pre_set (s);
00592
00593 if (xmlListSize (s->pre_steps) > 0) {
00594 cur_case_name = (xmlChar *)"pre_steps";
00595 cur_step_num = 0;
00596 memset (&dummy, 0x0, sizeof (td_case));
00597 dummy.case_res = CASE_PASS;
00598 dummy.dummy = 1;
00599 LOG_MSG (LOG_INFO, "Executing pre steps");
00600 xmlListWalk (s->pre_steps, prepost_steps_execute, &dummy);
00601 if (dummy.case_res != CASE_PASS) {
00602 LOG_MSG (LOG_INFO, "Pre steps failed. "
00603 "Test set %s aborted.", s->gen.name);
00604 xmlListWalk (s->cases, case_result_fail,
00605 global_failure ? global_failure :
00606 "pre_steps failed");
00607 goto short_circuit;
00608 }
00609 }
00610
00611 xmlListWalk (s->cases, process_case, s);
00612 if (xmlListSize (s->post_steps) > 0) {
00613 LOG_MSG (LOG_INFO, "Executing post steps");
00614 cur_case_name = (xmlChar *)"post_steps";
00615 cur_step_num = 0;
00616 memset (&dummy, 0x0, sizeof (td_case));
00617 dummy.case_res = CASE_PASS;
00618 dummy.dummy = 1;
00619 xmlListWalk (s->post_steps, prepost_steps_execute, &dummy);
00620 if (dummy.case_res == CASE_FAIL)
00621 LOG_MSG (LOG_INFO,
00622 "Post steps failed for %s.", s->gen.name);
00623 }
00624 xmlListWalk (s->gets, process_get, s);
00625
00626 short_circuit:
00627 write_post_set (s);
00628 if (xmlListSize (s->pre_steps) > 0)
00629 xmlListWalk (s->pre_steps, step_post_process, &dummy);
00630 if (xmlListSize (s->post_steps) > 0)
00631 xmlListWalk (s->post_steps, step_post_process, &dummy);
00632 xml_end_element();
00633 skip_all:
00634 td_set_delete (s);
00635 return;
00636 }
00637
00638
00639
00643 void td_process () {
00644 int retval;
00645 td_parser_callbacks cbs;
00646
00647 memset (&cbs, 0x0, sizeof(td_parser_callbacks));
00648
00649
00650
00651 cbs.test_td = process_td;
00652 cbs.test_td_end = end_td;
00653 cbs.test_hwiddetect = process_hwiddetect;
00654 cbs.test_suite = process_suite;
00655 cbs.test_suite_end = end_suite;
00656 cbs.test_set = process_set;
00657
00658 retval = td_register_callbacks (&cbs);
00659
00660
00661
00662
00663 LOG_MSG (LOG_INFO, "Starting to run tests...");
00664
00665 while (td_next_node() == 0);
00666
00667 LOG_MSG (LOG_INFO, "Finished running tests.");
00668 LOG_MSG (LOG_INFO, "Executed %d cases. Passed %d Failed %d",
00669 casecount, passcount, failcount);
00670 return;
00671 }
00672
00676 const char *current_set_name ()
00677 {
00678 if (current_set)
00679 return (char *)current_set->gen.name;
00680 return "";
00681 }
00682
00686 const char *current_case_name ()
00687 {
00688 return (char *)cur_case_name;
00689 }
00690
00694 int current_step_num ()
00695 {
00696 return cur_step_num;
00697 }
00698
00699
00700
00701
00702
00703