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.\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 (" -S, --syslog\n\t\tWrite log messages also to syslog.\n");
00154 printf (" -t [USER@]ADDRESS, --target=[USER@]ADDRESS\n\t\t"
00155 "Enable host-based testing. "
00156 "If given, commands are executed from\n\t\t"
00157 "test control PC (host) side. "
00158 "ADDRESS is the ipv4 adress of the\n\t\t"
00159 "system under test.\n");
00160
00161 return;
00162 }
00165 LOCAL void version()
00166 {
00167 #ifdef VERSIONSTR
00168 #define AS_STRING_(x) #x
00169 #define AS_STRING(x) AS_STRING_(x)
00170 printf ("testrunner-lite version %s\n", AS_STRING(VERSIONSTR));
00171 #else
00172 printf ("no version information available\n");
00173 #endif
00174 }
00175
00178 LOCAL void copyright () {
00179 printf ("testrunner-lite, © Nokia 2010 All rights reserved,\n"
00180 "licensed under the Gnu Lesser General Public License "
00181 "version 2.1,\n"
00182 "Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>\n");
00183 }
00184
00188 LOCAL int create_output_folder ()
00189 {
00190 int len;
00191 char *p;
00192 char *pwd, *cmd;
00193
00194 if ((p = strrchr (opts.output_filename, '/'))) {
00195 len = p - opts.output_filename;
00196 opts.output_folder = (char *)malloc (len + 2);
00197 memset (opts.output_folder, 0x00, len + 2);
00198 strncpy (opts.output_folder, opts.output_filename, len + 1);
00199
00200 } else {
00201 pwd = getenv ("PWD");
00202 if (!pwd) {
00203 LOG_MSG (LOG_ERR, "%s: getenv() failed %s\n",
00204 PROGNAME, strerror (errno));
00205 return 1;
00206 }
00207 opts.output_folder = (char *)malloc (strlen (pwd) + 2);
00208 strcpy (opts.output_folder, pwd);
00209 opts.output_folder[strlen(pwd)] = '/';
00210 opts.output_folder[strlen(pwd) + 1] = '\0';
00211 }
00212
00213 cmd = (char *)malloc (strlen(opts.output_folder) +
00214 strlen("mkdir -p ") + 1);
00215 sprintf (cmd, "mkdir -p %s", opts.output_folder);
00216
00217 if (system (cmd)) {
00218 LOG_MSG (LOG_ERR, "%s failed to create output "
00219 "directory %s\n",
00220 PROGNAME, opts.output_folder);
00221 free (cmd);
00222 return 1;
00223 }
00224
00225 free (cmd);
00226
00227 return 0;
00228 }
00229
00235 LOCAL int parse_remote_logger(char *url, testrunner_lite_options *opts) {
00236 if (url) {
00237 opts->remote_logger = malloc(strlen(url) + 1);
00238 strcpy(opts->remote_logger, url);
00239 return 0;
00240 } else {
00241 return 1;
00242 }
00243
00244 }
00245
00246
00252 LOCAL int parse_target_address(char *address, testrunner_lite_options *opts) {
00253 if (address) {
00254 opts->target_address = malloc(strlen(address) + 1);
00255 strcpy(opts->target_address, address);
00256 return 0;
00257 } else {
00258 return 1;
00259 }
00260
00261 }
00262
00263
00264
00265
00272 int main (int argc, char *argv[], char *envp[])
00273 {
00274 int h_flag = 0, a_flag = 0, m_flag = 0, A_flag = 0, V_flag = 0;
00275 int opt_char, option_idx;
00276 FILE *ifile = NULL;
00277 testrunner_lite_return_code retval = TESTRUNNER_LITE_OK;
00278 xmlChar *filter_string = NULL;
00279 struct option testrunnerlite_options[] =
00280 {
00281 {"help", no_argument, &h_flag, 1},
00282 {"version", no_argument, &V_flag, 1},
00283 {"file", required_argument, NULL, 'f'},
00284 {"output", required_argument, NULL, 'o'},
00285 {"format", required_argument, NULL, 'r'},
00286 {"environment", required_argument, NULL, 'e'},
00287 {"verbose", optional_argument, NULL, 'v'},
00288 {"syslog", no_argument, &opts.syslog_output, 1},
00289 {"automatic", no_argument, &a_flag, 1},
00290 {"manual", no_argument, &m_flag, 1},
00291 {"filter", required_argument, NULL, 'l'},
00292 {"logger", required_argument, NULL, 'L'},
00293 {"ci", no_argument, &opts.disable_schema},
00294 {"semantic", no_argument, &opts.semantic_schema},
00295 {"validate-only", no_argument, &A_flag},
00296 {"no-hwinfo", no_argument, &opts.skip_hwinfo, 1},
00297 {"target", required_argument, NULL, 't'},
00298 {0, 0, 0, 0}
00299 };
00300
00301
00302 LIBXML_TEST_VERSION
00303
00304 memset (&opts, 0x0, sizeof(testrunner_lite_options));
00305 memset (&hwinfo, 0x0, sizeof(hwinfo));
00306
00307 opts.output_type = OUTPUT_TYPE_XML;
00308 opts.run_automatic = opts.run_manual = 1;
00309 gettimeofday (&created, NULL);
00310
00311 copyright();
00312 if (argc == 1)
00313 h_flag = 1;
00314
00315 while (1) {
00316 option_idx = 0;
00317
00318 opt_char = getopt_long (argc, argv,
00319 ":hVaAHSsmcf:o:e:l:r:L:t:v::",
00320 testrunnerlite_options, &option_idx);
00321 if (opt_char == -1)
00322 break;
00323
00324 switch (opt_char)
00325 {
00326 case 'h':
00327 h_flag = 1;
00328 break;
00329 case 'V':
00330 V_flag = 1;
00331 break;
00332 case 'v':
00333 if (opts.log_level != 0)
00334 break;
00335
00336 if (optarg) {
00337 if (!strcmp (optarg, "INFO"))
00338 opts.log_level = LOG_LEVEL_INFO;
00339 if (!strcmp (optarg, "DEBUG")
00340 || !strcmp (optarg, "v"))
00341 opts.log_level = LOG_LEVEL_DEBUG;
00342 }
00343 else {
00344 opts.log_level = LOG_LEVEL_INFO;
00345 }
00346
00347 break;
00348 case 'a':
00349 a_flag = 1;
00350 break;
00351 case 'm':
00352 m_flag = 1;
00353 break;
00354 case 'c':
00355 opts.disable_schema = 1;
00356 break;
00357 case 's':
00358 opts.semantic_schema = 1;
00359 break;
00360 case 'r':
00361 if (!strcmp (optarg, "xml"))
00362 opts.output_type = OUTPUT_TYPE_XML;
00363 else if (!strcmp (optarg, "text"))
00364 opts.output_type = OUTPUT_TYPE_TXT;
00365 else {
00366 fprintf (stderr, "%s Unknown format %s\n",
00367 PROGNAME, optarg);
00368 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00369 goto OUT;
00370 }
00371 break;
00372 case 'f':
00373 ifile = fopen (optarg, "r");
00374 if (!ifile) {
00375 fprintf (stderr, "%s Failed to open %s %s\n",
00376 PROGNAME, optarg, strerror (errno));
00377 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00378 goto OUT;
00379 }
00380 fclose (ifile);
00381 opts.input_filename = malloc (strlen (optarg) + 1);
00382 strcpy (opts.input_filename, optarg);
00383 break;
00384 case 'o':
00385 opts.output_filename = malloc (strlen (optarg) + 1);
00386 strcpy (opts.output_filename, optarg);
00387 break;
00388 case 'e':
00389 opts.environment = malloc (strlen (optarg) + 1);
00390 strcpy (opts.environment, optarg);
00391 break;
00392 case 'A':
00393 A_flag = 1;
00394 break;
00395 case 'H':
00396 opts.skip_hwinfo = 1;
00397 break;
00398 case 'S':
00399 opts.syslog_output = 1;
00400 break;
00401 case 'L':
00402 if (parse_remote_logger(optarg, &opts) != 0) {
00403 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00404 goto OUT;
00405 }
00406 break;
00407 case 'l':
00408 if (filter_string) {
00409 filter_string = xmlStrcat (filter_string,
00410 BAD_CAST " ");
00411 filter_string = xmlStrcat (filter_string,
00412 BAD_CAST optarg);
00413 } else
00414 filter_string = xmlCharStrdup (optarg);
00415 break;
00416 case 't':
00417 if (parse_target_address(optarg, &opts) != 0) {
00418 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00419 goto OUT;
00420 }
00421 break;
00422 case ':':
00423 fprintf (stderr, "%s missing argument - exiting\n",
00424 PROGNAME);
00425 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00426 goto OUT;
00427 break;
00428 case '?':
00429 fprintf (stderr, "%s unknown option - exiting\n",
00430 PROGNAME);
00431 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00432 goto OUT;
00433 break;
00434 }
00435 }
00436
00437
00438
00439
00440 if (h_flag) {
00441 usage();
00442 goto OUT;
00443 }
00444 if (V_flag) {
00445 version();
00446 goto OUT;
00447 }
00448
00449 if (m_flag && a_flag) {
00450 fprintf (stderr,
00451 "%s: -a and -m are mutually exclusive\n",
00452 PROGNAME);
00453 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00454 goto OUT;
00455 }
00456
00457 if (m_flag)
00458 opts.run_automatic = 0;
00459 if (a_flag)
00460 opts.run_manual = 0;
00461
00462 if (!ifile) {
00463 fprintf (stderr,
00464 "%s: mandatory option missing -f input_file\n",
00465 PROGNAME);
00466 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00467 goto OUT;
00468 }
00469
00470
00471
00472 log_init (&opts);
00473
00474
00475
00476 #ifdef VERSIONSTR
00477 #define AS_STRING_(x) #x
00478 #define AS_STRING(x) AS_STRING_(x)
00479 LOG_MSG (LOG_INFO, "Version %s", AS_STRING(VERSIONSTR));
00480 #endif
00481
00482
00483
00484 if (filter_string) {
00485 init_filters();
00486 if (parse_filter_string ((char *)filter_string) != 0) {
00487 LOG_MSG (LOG_ERR, "filter parsing failed .. exiting");
00488 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00489 goto OUT;
00490 }
00491 }
00492
00493
00494
00495 executor_init (&opts);
00496
00497
00498
00499 retval = parse_test_definition (&opts);
00500 if (A_flag) {
00501 printf ("%s: %s %s\n", PROGNAME, opts.input_filename, retval ?
00502 "fails to validate" : "validates");
00503 goto OUT;
00504 }
00505 if (retval)
00506 goto OUT;
00507
00508 if (!opts.output_filename) {
00509 fprintf (stderr,
00510 "%s: mandatory option missing -o output_file\n",
00511 PROGNAME);
00512 retval = TESTRUNNER_LITE_INVALID_ARGUMENTS;
00513 goto OUT;
00514 }
00515 if (create_output_folder(&opts)) {
00516 retval = TESTRUNNER_LITE_OUTPUT_FOLDER_CREATE_FAIL;
00517 goto OUT;
00518 }
00519
00520 if (!opts.environment) {
00521 opts.environment = (char *)malloc (strlen ("hardware") + 1);
00522 strcpy (opts.environment, "hardware");
00523 }
00524
00525
00526
00527
00528 retval = td_reader_init(&opts);
00529 if (retval) {
00530 retval = TESTRUNNER_LITE_XML_READER_FAIL;
00531 goto OUT;
00532 }
00533
00534
00535
00536 if (!opts.skip_hwinfo)
00537 read_hwinfo (&hwinfo);
00538
00539
00540
00541
00542 retval = init_result_logger(&opts, &hwinfo);
00543 if (retval) {
00544 retval = TESTRUNNER_LITE_RESULT_LOGGING_FAIL;
00545 goto OUT;
00546 }
00547
00548
00549
00550 td_process();
00551
00552 executor_close();
00553 td_reader_close();
00554 close_result_logger();
00555 LOG_MSG (LOG_INFO, "Results were written to: %s", opts.output_filename);
00556 LOG_MSG (LOG_INFO, "Finished!");
00557 cleanup_filters();
00558 log_close();
00559 OUT:
00560 if (opts.input_filename) free (opts.input_filename);
00561 if (opts.output_filename) free (opts.output_filename);
00562 if (opts.output_folder) free (opts.output_folder);
00563 if (opts.environment) free (opts.environment);
00564 if (opts.remote_logger) free (opts.remote_logger);
00565 if (opts.target_address) free (opts.target_address);
00566 if (filter_string) free (filter_string);
00567 if (bail_out) retval = TESTRUNNER_LITE_SSH_FAIL;
00568
00569 return retval;
00570 }
00571
00572
00573
00574
00575
00576
00577