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 "testdefinitionprocessor.h"
00044 #include "testfilters.h"
00045 #include "executor.h"
00046 #include "remote_executor.h"
00047 #include "manual_executor.h"
00048 #include "utils.h"
00049 #include "hwinfo.h"
00050 #include "log.h"
00051
00052
00053
00054
00055
00056
00057
00058 extern char* optarg;
00059 extern int bail_out;
00060
00061
00062
00063
00064
00065
00066 struct timeval created;
00067 testrunner_lite_options opts;
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 LOCAL td_suite *current_suite = NULL;
00079 LOCAL hw_info hwinfo;
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 LOCAL void usage();
00092
00093 LOCAL void version();
00094
00095 LOCAL void copyright();
00096
00097 LOCAL int create_output_folder ();
00098
00099
00100
00101
00102
00103
00104
00107 LOCAL void usage()
00108 {
00109 printf ("\nUsage: testrunner-lite [options]\n");
00110 printf ("Example: testrunner-lite -f tests.xml -o ~/results.xml "
00111 "-e hardware\n");
00112 printf ("\nOptions:\n");
00113 printf (" -h, --help\tShow this help message and exit.\n");
00114 printf (" -V, --version\tDisplay version and exit.\n");
00115 printf (" -f FILE, --file=FILE\tInput file with test definitions "
00116 "in XML (required).\n");
00117 printf (" -o FILE, --output=FILE\n\t\t"
00118 "Output file for test results (required).\n");
00119 printf (" -r FORMAT, --format=FORMAT\n\t\t"
00120 "Output file format. FORMAT can be xml or text.\n\t\t"
00121 "Default: xml\n");
00122 printf (" -e ENVIRONMENT, --environment=ENVIRONMENT\n\t\t"
00123 "Target test environment. Default: hardware\n");
00124 printf (" -v, -vv, --verbose[={INFO|DEBUG}]\n\t\t"
00125 "Enable verbosity mode; -v and --verbose=INFO "
00126 "are equivalent\n\t\t"
00127 "outputting INFO, ERROR and WARNING messages.\n\t\t"
00128 "Similarly -vv and --verbose=DEBUG "
00129 "are equivalent, outputting\n\t\t"
00130 "also debug messages. Default behaviour is silent mode.\n");
00131 printf(" -L, --logger=URL\n\t\t"
00132 "Remote HTTP logger for log messages. URL format is\n\t\t"
00133 "[http://]host[:port][/path/], "
00134 "where host may be a hostname\n\t\t"
00135 "or an IPv4 address.\n");
00136 printf (" -a, --automatic\tEnable only automatic tests "
00137 "to be executed.\n");
00138 printf (" -m, --manual\tEnable only manual tests to be executed.\n");
00139
00140 printf (" -l FILTER, --filter=FILTER\n\t\t"
00141 "Filtering option to select tests (not) to be executed.\n\t\t"
00142 "E.g. '-testcase=bad_test -type=unknown' first disables\n\t\t"
00143 "test case named as bad_test. Next, all tests with type\n\t\t"
00144 "unknown are disabled. The remaining tests will be\n\t\t"
00145 "executed. (Currently supported filter type are: \n\t\t"
00146 "testset,requirement,feature and type)\n");
00147 printf (" -c, --ci\tDisable validation of test "
00148 "definition against schema.\n");
00149 printf (" -s, --semantic\n\t\tEnable validation of test "
00150 "definition against stricter (semantics) schema.\n");
00151 printf (" -A, --validate-only\n\t\tDo only input xml validation, "
00152 "do not execute tests.\n");
00153 printf (" -H, --no-hwinfo\n\t\tSkip hwinfo obtaining.\n");
00154 printf (" -P, --print-step-output\n\t\tOutput standard streams from"
00155 " programs started in steps\n");
00156 printf (" -S, --syslog\n\t\tWrite log messages also to syslog.\n");
00157 printf (" -t [USER@]ADDRESS, --target=[USER@]ADDRESS\n\t\t"
00158 "Enable host-based testing. "
00159 "If given, commands are executed from\n\t\t"
00160 "test control PC (host) side. "
00161 "ADDRESS is the ipv4 adress of the\n\t\t"
00162 "system under test.\n");
00163
00164 return;
00165 }
00168 LOCAL void version()
00169 {
00170 #ifdef VERSIONSTR
00171 #define AS_STRING_(x) #x
00172 #define AS_STRING(x) AS_STRING_(x)
00173 printf ("testrunner-lite version %s\n", AS_STRING(VERSIONSTR));
00174 #else
00175 printf ("no version information available\n");
00176 #endif
00177 }
00178
00181 LOCAL void copyright () {
00182 printf ("testrunner-lite, © Nokia 2010 All rights reserved,\n"
00183 "licensed under the Gnu Lesser General Public License "
00184 "version 2.1,\n"
00185 "Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>\n");
00186 }
00187
00191 LOCAL int create_output_folder ()
00192 {
00193 int len;
00194 char *p;
00195 char *pwd, *cmd;
00196
00197 if ((p = strrchr (opts.output_filename, '/'))) {
00198 len = p - opts.output_filename;
00199 opts.output_folder = (char *)malloc (len + 2);
00200 memset (opts.output_folder, 0x00, len + 2);
00201 strncpy (opts.output_folder, opts.output_filename, len + 1);
00202
00203 } else {
00204 pwd = getenv ("PWD");
00205 if (!pwd) {
00206 LOG_MSG (LOG_ERR, "%s: getenv() failed %s\n",
00207 PROGNAME, strerror (errno));
00208 return 1;
00209 }
00210 opts.output_folder = (char *)malloc (strlen (pwd) + 2);
00211 strcpy (opts.output_folder, pwd);
00212 opts.output_folder[strlen(pwd)] = '/';
00213 opts.output_folder[strlen(pwd) + 1] = '\0';
00214 }
00215
00216 cmd = (char *)malloc (strlen(opts.output_folder) +
00217 strlen("mkdir -p ") + 1);
00218 sprintf (cmd, "mkdir -p %s", opts.output_folder);
00219
00220 if (system (cmd)) {
00221 LOG_MSG (LOG_ERR, "%s failed to create output "
00222 "directory %s\n",
00223 PROGNAME, opts.output_folder);
00224 free (cmd);
00225 return 1;
00226 }
00227
00228 free (cmd);
00229
00230 return 0;
00231 }
00232
00238 LOCAL int parse_remote_logger(char *url, testrunner_lite_options *opts) {
00239 if (url) {
00240 opts->remote_logger = malloc(strlen(url) + 1);
00241 strcpy(opts->remote_logger, url);
00242 return 0;
00243 } else {
00244 return 1;
00245 }
00246
00247 }
00248
00249
00255 LOCAL int parse_target_address(char *address, testrunner_lite_options *opts) {
00256 if (address) {
00257 opts->target_address = malloc(strlen(address) + 1);
00258 strcpy(opts->target_address, address);
00259 return 0;
00260 } else {
00261 return 1;
00262 }
00263
00264 }
00265
00266
00267
00268
00275 int main (int argc, char *argv[], char *envp[])
00276 {
00277 int h_flag = 0, a_flag = 0, m_flag = 0, A_flag = 0, V_flag = 0;
00278 int opt_char, option_idx;
00279 FILE *ifile = NULL;
00280 testrunner_lite_return_code retval = TESTRUNNER_LITE_OK;
00281 xmlChar *filter_string = NULL;
00282 struct option testrunnerlite_options[] =
00283 {
00284 {"help", no_argument, &h_flag, 1},
00285 {"version", no_argument, &V_flag, 1},
00286 {"file", required_argument, NULL, 'f'},
00287 {"output", required_argument, NULL, 'o'},
00288 {"format", required_argument, NULL, 'r'},
00289 {"environment", required_argument, NULL, 'e'},
00290 {"verbose", optional_argument, NULL, 'v'},
00291 {"syslog", no_argument, &opts.syslog_output, 1},
00292 {"automatic", no_argument, &a_flag, 1},
00293 {"manual", no_argument, &m_flag, 1},
00294 {"filter", required_argument, NULL, 'l'},
00295 {"logger", required_argument, NULL, 'L'},
00296 {"ci", no_argument, &opts.disable_schema},
00297 {"semantic", no_argument, &opts.semantic_schema},
00298 {"validate-only", no_argument, &A_flag},
00299 {"no-hwinfo", no_argument, &opts.skip_hwinfo, 1},
00300 {"target", required_argument, NULL, 't'},
00301 {"print-step-output", no_argument,
00302 &opts.print_step_output, 1},
00303 {0, 0, 0, 0}
00304 };
00305
00306
00307 LIBXML_TEST_VERSION
00308
00309 memset (&opts, 0x0, sizeof(testrunner_lite_options));
00310 memset (&hwinfo, 0x0, sizeof(hwinfo));
00311
00312 opts.output_type = OUTPUT_TYPE_XML;
00313 opts.run_automatic = opts.run_manual = 1;
00314 gettimeofday (&created, NULL);
00315 signal (SIGINT, handle_sigint);
00316 signal (SIGTERM, handle_sigterm);
00317 copyright();
00318 if (argc == 1)
00319 h_flag = 1;
00320
00321 while (1) {
00322 option_idx = 0;
00323
00324 opt_char = getopt_long (argc, argv,
00325 ":hVaAHSsmcPf:o:e:l:r:L:t:v::",
00326 testrunnerlite_options, &option_idx);
00327 if (opt_char == -1)
00328 break;
00329
00330 switch (opt_char)
00331 {
00332 case 'h':
00333 h_flag = 1;
00334 break;
00335 case 'V':
00336 V_flag = 1;
00337 break;
00338 case 'v':
00339 if (opts.log_level != 0)
00340 break;
00341
00342 if (optarg) {
00343 if (!strcmp (optarg, "INFO"))
00344 opts.log_level = LOG_LEVEL_INFO;
00345 if (!strcmp (optarg, "DEBUG")
00346 || !strcmp (optarg, "v"))
00347 opts.log_level = LOG_LEVEL_DEBUG;
00348 }
00349 else {
00350 opts.log_level = LOG_LEVEL_INFO;
00351 }
00352
00353 break;
00354 case 'a':
00355 a_flag = 1;
00356 break;
00357 case 'm':
00358 m_flag = 1;
00359 break;
00360 case 'c':
00361 opts.disable_schema = 1;
00362 break;
00363 case 's':
00364 opts.semantic_schema = 1;
00365 break;
00366 case 'r':
00367 if (!strcmp (optarg, "xml"))
00368 opts.output_type = OUTPUT_TYPE_XML;
00369 else if (!strcmp (optarg, "text"))
00370 opts.output_type = OUTPUT_TYPE_TXT;
00371 else {
00372 fprintf (stderr, "%s Unknown format %s\n",
00373 PROGNAME, optarg);
00374 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00375 goto OUT;
00376 }
00377 break;
00378 case 'f':
00379 ifile = fopen (optarg, "r");
00380 if (!ifile) {
00381 fprintf (stderr, "%s Failed to open %s %s\n",
00382 PROGNAME, optarg, strerror (errno));
00383 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00384 goto OUT;
00385 }
00386 fclose (ifile);
00387 opts.input_filename = malloc (strlen (optarg) + 1);
00388 strcpy (opts.input_filename, optarg);
00389 break;
00390 case 'o':
00391 opts.output_filename = malloc (strlen (optarg) + 1);
00392 strcpy (opts.output_filename, optarg);
00393 break;
00394 case 'e':
00395 opts.environment = malloc (strlen (optarg) + 1);
00396 strcpy (opts.environment, optarg);
00397 break;
00398 case 'A':
00399 A_flag = 1;
00400 break;
00401 case 'H':
00402 opts.skip_hwinfo = 1;
00403 break;
00404 case 'S':
00405 opts.syslog_output = 1;
00406 break;
00407 case 'L':
00408 if (parse_remote_logger(optarg, &opts) != 0) {
00409 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00410 goto OUT;
00411 }
00412 break;
00413 case 'l':
00414 if (filter_string) {
00415 filter_string = xmlStrcat (filter_string,
00416 BAD_CAST " ");
00417 filter_string = xmlStrcat (filter_string,
00418 BAD_CAST optarg);
00419 } else
00420 filter_string = xmlCharStrdup (optarg);
00421 break;
00422 case 't':
00423 if (parse_target_address(optarg, &opts) != 0) {
00424 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00425 goto OUT;
00426 }
00427 break;
00428 case 'P':
00429 opts.print_step_output = 1;
00430 break;
00431 case ':':
00432 fprintf (stderr, "%s missing argument - exiting\n",
00433 PROGNAME);
00434 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00435 goto OUT;
00436 break;
00437 case '?':
00438 fprintf (stderr, "%s unknown option - exiting\n",
00439 PROGNAME);
00440 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00441 goto OUT;
00442 break;
00443 }
00444 }
00445
00446
00447
00448
00449 if (h_flag) {
00450 usage();
00451 goto OUT;
00452 }
00453 if (V_flag) {
00454 version();
00455 goto OUT;
00456 }
00457
00458 if (m_flag && a_flag) {
00459 fprintf (stderr,
00460 "%s: -a and -m are mutually exclusive\n",
00461 PROGNAME);
00462 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00463 goto OUT;
00464 }
00465
00466 if (m_flag)
00467 opts.run_automatic = 0;
00468 if (a_flag)
00469 opts.run_manual = 0;
00470
00471 if (!ifile) {
00472 fprintf (stderr,
00473 "%s: mandatory option missing -f input_file\n",
00474 PROGNAME);
00475 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00476 goto OUT;
00477 }
00478
00479
00480
00481 log_init (&opts);
00482
00483
00484
00485 #ifdef VERSIONSTR
00486 #define AS_STRING_(x) #x
00487 #define AS_STRING(x) AS_STRING_(x)
00488 LOG_MSG (LOG_INFO, "Version %s", AS_STRING(VERSIONSTR));
00489 #endif
00490
00491
00492
00493 if (filter_string) {
00494 init_filters();
00495 if (parse_filter_string ((char *)filter_string) != 0) {
00496 LOG_MSG (LOG_ERR, "filter parsing failed .. exiting");
00497 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00498 goto OUT;
00499 }
00500 }
00501
00502
00503
00504 executor_init (&opts);
00505
00506
00507
00508 retval = parse_test_definition (&opts);
00509 if (A_flag) {
00510 printf ("%s: %s %s\n", PROGNAME, opts.input_filename, retval ?
00511 "fails to validate" : "validates");
00512 goto OUT;
00513 }
00514 if (retval)
00515 goto OUT;
00516
00517 if (!opts.output_filename) {
00518 fprintf (stderr,
00519 "%s: mandatory option missing -o output_file\n",
00520 PROGNAME);
00521 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00522 goto OUT;
00523 }
00524 if (create_output_folder(&opts)) {
00525 retval = TESTRUNNER_LITE_OUTPUT_FOLDER_CREATE_FAIL;
00526 goto OUT;
00527 }
00528
00529 if (!opts.environment) {
00530 opts.environment = (char *)malloc (strlen ("hardware") + 1);
00531 strcpy (opts.environment, "hardware");
00532 }
00533
00534
00535
00536
00537 retval = td_reader_init(&opts);
00538 if (retval) {
00539 retval = TESTRUNNER_LITE_XML_READER_FAIL;
00540 goto OUT;
00541 }
00542
00543
00544
00545 if (!opts.skip_hwinfo)
00546 read_hwinfo (&hwinfo);
00547
00548
00549
00550
00551 retval = init_result_logger(&opts, &hwinfo);
00552 if (retval) {
00553 retval = TESTRUNNER_LITE_RESULT_LOGGING_FAIL;
00554 goto OUT;
00555 }
00556
00557
00558
00559 td_process();
00560
00561 executor_close();
00562 td_reader_close();
00563 close_result_logger();
00564 LOG_MSG (LOG_INFO, "Results were written to: %s", opts.output_filename);
00565 LOG_MSG (LOG_INFO, "Finished!");
00566 cleanup_filters();
00567 log_close();
00568 OUT:
00569 if (opts.input_filename) free (opts.input_filename);
00570 if (opts.output_filename) free (opts.output_filename);
00571 if (opts.output_folder) free (opts.output_folder);
00572 if (opts.environment) free (opts.environment);
00573 if (opts.remote_logger) free (opts.remote_logger);
00574 if (opts.target_address) free (opts.target_address);
00575 if (filter_string) free (filter_string);
00576 if (bail_out == 255+SIGINT) {
00577 signal (SIGINT, SIG_DFL);
00578 raise (SIGINT);
00579 } else if (bail_out == 255+SIGTERM) {
00580 signal (SIGTERM, SIG_DFL);
00581 raise (SIGTERM);
00582 } else if (bail_out) retval = TESTRUNNER_LITE_SSH_FAIL;
00583
00584 return retval;
00585 }
00586
00587
00588
00589
00590
00591
00592