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 hw_info hwinfo;
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 LOCAL void usage();
00091
00092 LOCAL void version();
00093
00094 LOCAL void copyright();
00095
00096 LOCAL int create_output_folder ();
00097
00098
00099
00100
00101
00102
00103
00106 LOCAL void usage()
00107 {
00108 printf ("\nUsage: testrunner-lite [options]\n");
00109 printf ("Example: testrunner-lite -f tests.xml -o ~/results.xml "
00110 "-e hardware\n");
00111 printf ("\nOptions:\n");
00112 printf (" -h, --help\tShow this help message and exit.\n");
00113 printf (" -V, --version\tDisplay version and exit.\n");
00114 printf (" -f FILE, --file=FILE\tInput file with test definitions "
00115 "in XML (required).\n");
00116 printf (" -o FILE, --output=FILE\n\t\t"
00117 "Output file for test results (required).\n");
00118 printf (" -r FORMAT, --format=FORMAT\n\t\t"
00119 "Output file format. FORMAT can be xml or text.\n\t\t"
00120 "Default: xml\n");
00121 printf (" -e ENVIRONMENT, --environment=ENVIRONMENT\n\t\t"
00122 "Target test environment. Default: hardware\n");
00123 printf (" -v, -vv, --verbose[={INFO|DEBUG}]\n\t\t"
00124 "Enable verbosity mode; -v and --verbose=INFO "
00125 "are equivalent\n\t\t"
00126 "outputting INFO, ERROR and WARNING messages.\n\t\t"
00127 "Similarly -vv and --verbose=DEBUG "
00128 "are equivalent, outputting\n\t\t"
00129 "also debug messages. Default behaviour is silent mode.\n");
00130 printf(" -L, --logger=URL\n\t\t"
00131 "Remote HTTP logger for log messages. URL format is\n\t\t"
00132 "[http://]host[:port][/path/], "
00133 "where host may be a hostname\n\t\t"
00134 "or an IPv4 address.\n");
00135 printf (" -a, --automatic\tEnable only automatic tests "
00136 "to be executed.\n");
00137 printf (" -m, --manual\tEnable only manual tests to be executed.\n");
00138
00139 printf (" -l FILTER, --filter=FILTER\n\t\t"
00140 "Filtering option to select tests (not) to be executed.\n\t\t"
00141 "E.g. '-testcase=bad_test -type=unknown' first disables\n\t\t"
00142 "test case named as bad_test. Next, all tests with type\n\t\t"
00143 "unknown are disabled. The remaining tests will be\n\t\t"
00144 "executed. (Currently supported filter type are: \n\t\t"
00145 "testset,requirement,feature and type)\n");
00146 printf (" -c, --ci\tDisable validation of test "
00147 "definition against schema.\n");
00148 printf (" -s, --semantic\n\t\tEnable validation of test "
00149 "definition against stricter (semantics) schema.\n");
00150 printf (" -A, --validate-only\n\t\tDo only input xml validation, "
00151 "do not execute tests.\n");
00152 printf (" -H, --no-hwinfo\n\t\tSkip hwinfo obtaining.\n");
00153 printf (" -P, --print-step-output\n\t\tOutput standard streams from"
00154 " programs started in steps\n");
00155 printf (" -S, --syslog\n\t\tWrite log messages also to syslog.\n");
00156 printf (" -t [USER@]ADDRESS, --target=[USER@]ADDRESS\n\t\t"
00157 "Enable host-based testing. "
00158 "If given, commands are executed from\n\t\t"
00159 "test control PC (host) side. "
00160 "ADDRESS is the ipv4 adress of the\n\t\t"
00161 "system under test.\n");
00162
00163 return;
00164 }
00167 LOCAL void version()
00168 {
00169 #ifdef VERSIONSTR
00170 #define AS_STRING_(x) #x
00171 #define AS_STRING(x) AS_STRING_(x)
00172 printf ("testrunner-lite version %s\n", AS_STRING(VERSIONSTR));
00173 #else
00174 printf ("no version information available\n");
00175 #endif
00176 }
00177
00180 LOCAL void copyright () {
00181 printf ("testrunner-lite, © Nokia 2010 All rights reserved,\n"
00182 "licensed under the Gnu Lesser General Public License "
00183 "version 2.1,\n"
00184 "Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>\n");
00185 }
00186
00190 LOCAL int create_output_folder ()
00191 {
00192 int len;
00193 char *p;
00194 char *pwd, *cmd;
00195
00196 if ((p = strrchr (opts.output_filename, '/'))) {
00197 len = p - opts.output_filename;
00198 opts.output_folder = (char *)malloc (len + 2);
00199 memset (opts.output_folder, 0x00, len + 2);
00200 strncpy (opts.output_folder, opts.output_filename, len + 1);
00201
00202 } else {
00203 pwd = getenv ("PWD");
00204 if (!pwd) {
00205 LOG_MSG (LOG_ERR, "%s: getenv() failed %s\n",
00206 PROGNAME, strerror (errno));
00207 return 1;
00208 }
00209 opts.output_folder = (char *)malloc (strlen (pwd) + 2);
00210 strcpy (opts.output_folder, pwd);
00211 opts.output_folder[strlen(pwd)] = '/';
00212 opts.output_folder[strlen(pwd) + 1] = '\0';
00213 }
00214
00215 cmd = (char *)malloc (strlen(opts.output_folder) +
00216 strlen("mkdir -p ") + 1);
00217 sprintf (cmd, "mkdir -p %s", opts.output_folder);
00218
00219 if (system (cmd)) {
00220 LOG_MSG (LOG_ERR, "%s failed to create output "
00221 "directory %s\n",
00222 PROGNAME, opts.output_folder);
00223 free (cmd);
00224 return 1;
00225 }
00226
00227 free (cmd);
00228
00229 return 0;
00230 }
00231
00237 LOCAL int parse_remote_logger(char *url, testrunner_lite_options *opts) {
00238 if (url) {
00239 opts->remote_logger = malloc(strlen(url) + 1);
00240 strcpy(opts->remote_logger, url);
00241 return 0;
00242 } else {
00243 return 1;
00244 }
00245
00246 }
00247
00248
00254 LOCAL int parse_target_address(char *address, testrunner_lite_options *opts) {
00255 if (address) {
00256 opts->target_address = malloc(strlen(address) + 1);
00257 strcpy(opts->target_address, address);
00258 return 0;
00259 } else {
00260 return 1;
00261 }
00262
00263 }
00264
00265
00266
00267
00274 int main (int argc, char *argv[], char *envp[])
00275 {
00276 int h_flag = 0, a_flag = 0, m_flag = 0, A_flag = 0, V_flag = 0;
00277 int opt_char, option_idx;
00278 FILE *ifile = NULL;
00279 testrunner_lite_return_code retval = TESTRUNNER_LITE_OK;
00280 xmlChar *filter_string = NULL;
00281 struct option testrunnerlite_options[] =
00282 {
00283 {"help", no_argument, &h_flag, 1},
00284 {"version", no_argument, &V_flag, 1},
00285 {"file", required_argument, NULL, 'f'},
00286 {"output", required_argument, NULL, 'o'},
00287 {"format", required_argument, NULL, 'r'},
00288 {"environment", required_argument, NULL, 'e'},
00289 {"verbose", optional_argument, NULL, 'v'},
00290 {"syslog", no_argument, &opts.syslog_output, 1},
00291 {"automatic", no_argument, &a_flag, 1},
00292 {"manual", no_argument, &m_flag, 1},
00293 {"filter", required_argument, NULL, 'l'},
00294 {"logger", required_argument, NULL, 'L'},
00295 {"ci", no_argument, &opts.disable_schema},
00296 {"semantic", no_argument, &opts.semantic_schema},
00297 {"validate-only", no_argument, &A_flag},
00298 {"no-hwinfo", no_argument, &opts.skip_hwinfo, 1},
00299 {"target", required_argument, NULL, 't'},
00300 {"print-step-output", no_argument,
00301 &opts.print_step_output, 1},
00302 {0, 0, 0, 0}
00303 };
00304
00305
00306 LIBXML_TEST_VERSION
00307
00308 memset (&opts, 0x0, sizeof(testrunner_lite_options));
00309 memset (&hwinfo, 0x0, sizeof(hwinfo));
00310
00311 opts.output_type = OUTPUT_TYPE_XML;
00312 opts.run_automatic = opts.run_manual = 1;
00313 gettimeofday (&created, NULL);
00314 signal (SIGINT, handle_sigint);
00315 signal (SIGTERM, handle_sigterm);
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 case ':':
00431 fprintf (stderr, "%s missing argument - exiting\n",
00432 PROGNAME);
00433 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00434 goto OUT;
00435 break;
00436 case '?':
00437 fprintf (stderr, "%s unknown option - exiting\n",
00438 PROGNAME);
00439 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00440 goto OUT;
00441 break;
00442 }
00443 }
00444
00445
00446
00447
00448 if (h_flag) {
00449 usage();
00450 goto OUT;
00451 }
00452 if (V_flag) {
00453 version();
00454 goto OUT;
00455 }
00456
00457 if (m_flag && a_flag) {
00458 fprintf (stderr,
00459 "%s: -a and -m are mutually exclusive\n",
00460 PROGNAME);
00461 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00462 goto OUT;
00463 }
00464
00465 if (m_flag)
00466 opts.run_automatic = 0;
00467 if (a_flag)
00468 opts.run_manual = 0;
00469
00470 if (!ifile) {
00471 fprintf (stderr,
00472 "%s: mandatory option missing -f input_file\n",
00473 PROGNAME);
00474 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00475 goto OUT;
00476 }
00477
00478
00479
00480 log_init (&opts);
00481
00482
00483
00484 #ifdef VERSIONSTR
00485 #define AS_STRING_(x) #x
00486 #define AS_STRING(x) AS_STRING_(x)
00487 LOG_MSG (LOG_INFO, "Version %s", AS_STRING(VERSIONSTR));
00488 #endif
00489
00490
00491
00492 if (filter_string) {
00493 init_filters();
00494 if (parse_filter_string ((char *)filter_string) != 0) {
00495 LOG_MSG (LOG_ERR, "filter parsing failed .. exiting");
00496 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00497 goto OUT;
00498 }
00499 }
00500
00501
00502
00503 executor_init (&opts);
00504
00505
00506
00507 retval = parse_test_definition (&opts);
00508 if (A_flag) {
00509 printf ("%s: %s %s\n", PROGNAME, opts.input_filename, retval ?
00510 "fails to validate" : "validates");
00511 goto OUT;
00512 }
00513 if (retval)
00514 goto OUT;
00515
00516 if (!opts.output_filename) {
00517 fprintf (stderr,
00518 "%s: mandatory option missing -o output_file\n",
00519 PROGNAME);
00520 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00521 goto OUT;
00522 }
00523 if (create_output_folder(&opts)) {
00524 retval = TESTRUNNER_LITE_OUTPUT_FOLDER_CREATE_FAIL;
00525 goto OUT;
00526 }
00527
00528 if (!opts.environment) {
00529 opts.environment = (char *)malloc (strlen ("hardware") + 1);
00530 strcpy (opts.environment, "hardware");
00531 }
00532
00533
00534
00535
00536 retval = td_reader_init(&opts);
00537 if (retval) {
00538 retval = TESTRUNNER_LITE_XML_READER_FAIL;
00539 goto OUT;
00540 }
00541
00542
00543
00544 if (!opts.skip_hwinfo)
00545 read_hwinfo (&hwinfo);
00546
00547
00548
00549
00550 retval = init_result_logger(&opts, &hwinfo);
00551 if (retval) {
00552 retval = TESTRUNNER_LITE_RESULT_LOGGING_FAIL;
00553 goto OUT;
00554 }
00555
00556
00557
00558 td_process();
00559
00560 executor_close();
00561 td_reader_close();
00562 close_result_logger();
00563 LOG_MSG (LOG_INFO, "Results were written to: %s", opts.output_filename);
00564 LOG_MSG (LOG_INFO, "Finished!");
00565 cleanup_filters();
00566 log_close();
00567 OUT:
00568 if (opts.input_filename) free (opts.input_filename);
00569 if (opts.output_filename) free (opts.output_filename);
00570 if (opts.output_folder) free (opts.output_folder);
00571 if (opts.environment) free (opts.environment);
00572 if (opts.remote_logger) free (opts.remote_logger);
00573 if (opts.target_address) free (opts.target_address);
00574 if (filter_string) free (filter_string);
00575 if (bail_out == 255+SIGINT) {
00576 signal (SIGINT, SIG_DFL);
00577 raise (SIGINT);
00578 } else if (bail_out == 255+SIGTERM) {
00579 signal (SIGTERM, SIG_DFL);
00580 raise (SIGTERM);
00581 } else if (bail_out) retval = TESTRUNNER_LITE_SSH_FAIL;
00582
00583 return retval;
00584 }
00585
00586
00587
00588
00589
00590
00591