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 copyright();
00317 if (argc == 1)
00318 h_flag = 1;
00319
00320 while (1) {
00321 option_idx = 0;
00322
00323 opt_char = getopt_long (argc, argv,
00324 ":hVaAHSsmcPf:o:e:l:r:L:t:v::",
00325 testrunnerlite_options, &option_idx);
00326 if (opt_char == -1)
00327 break;
00328
00329 switch (opt_char)
00330 {
00331 case 'h':
00332 h_flag = 1;
00333 break;
00334 case 'V':
00335 V_flag = 1;
00336 break;
00337 case 'v':
00338 if (opts.log_level != 0)
00339 break;
00340
00341 if (optarg) {
00342 if (!strcmp (optarg, "INFO"))
00343 opts.log_level = LOG_LEVEL_INFO;
00344 if (!strcmp (optarg, "DEBUG")
00345 || !strcmp (optarg, "v"))
00346 opts.log_level = LOG_LEVEL_DEBUG;
00347 }
00348 else {
00349 opts.log_level = LOG_LEVEL_INFO;
00350 }
00351
00352 break;
00353 case 'a':
00354 a_flag = 1;
00355 break;
00356 case 'm':
00357 m_flag = 1;
00358 break;
00359 case 'c':
00360 opts.disable_schema = 1;
00361 break;
00362 case 's':
00363 opts.semantic_schema = 1;
00364 break;
00365 case 'r':
00366 if (!strcmp (optarg, "xml"))
00367 opts.output_type = OUTPUT_TYPE_XML;
00368 else if (!strcmp (optarg, "text"))
00369 opts.output_type = OUTPUT_TYPE_TXT;
00370 else {
00371 fprintf (stderr, "%s Unknown format %s\n",
00372 PROGNAME, optarg);
00373 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00374 goto OUT;
00375 }
00376 break;
00377 case 'f':
00378 ifile = fopen (optarg, "r");
00379 if (!ifile) {
00380 fprintf (stderr, "%s Failed to open %s %s\n",
00381 PROGNAME, optarg, strerror (errno));
00382 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00383 goto OUT;
00384 }
00385 fclose (ifile);
00386 opts.input_filename = malloc (strlen (optarg) + 1);
00387 strcpy (opts.input_filename, optarg);
00388 break;
00389 case 'o':
00390 opts.output_filename = malloc (strlen (optarg) + 1);
00391 strcpy (opts.output_filename, optarg);
00392 break;
00393 case 'e':
00394 opts.environment = malloc (strlen (optarg) + 1);
00395 strcpy (opts.environment, optarg);
00396 break;
00397 case 'A':
00398 A_flag = 1;
00399 break;
00400 case 'H':
00401 opts.skip_hwinfo = 1;
00402 break;
00403 case 'S':
00404 opts.syslog_output = 1;
00405 break;
00406 case 'L':
00407 if (parse_remote_logger(optarg, &opts) != 0) {
00408 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00409 goto OUT;
00410 }
00411 break;
00412 case 'l':
00413 if (filter_string) {
00414 filter_string = xmlStrcat (filter_string,
00415 BAD_CAST " ");
00416 filter_string = xmlStrcat (filter_string,
00417 BAD_CAST optarg);
00418 } else
00419 filter_string = xmlCharStrdup (optarg);
00420 break;
00421 case 't':
00422 if (parse_target_address(optarg, &opts) != 0) {
00423 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00424 goto OUT;
00425 }
00426 break;
00427 case 'P':
00428 opts.print_step_output = 1;
00429 break;
00430
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) retval = TESTRUNNER_LITE_SSH_FAIL;
00580
00581 return retval;
00582 }
00583
00584
00585
00586
00587
00588
00589