tag_report.c revision 354ebb48db8e66a853a58379a4808d5dcd1ceac3
1/* 2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it is 13 * free of the rightful claim of any third person regarding infringement 14 * or the like. Any license provided herein, whether implied or 15 * otherwise, applies only to this software file. Patent licenses, if 16 * any, provided herein do not apply to combinations of this program with 17 * other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write the Free Software Foundation, Inc., 21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 24 * Mountain View, CA 94043, or: 25 * 26 * http://www.sgi.com 27 * 28 * For further information regarding this notice, see: 29 * 30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ 31 * 32 */ 33/* $Id: tag_report.c,v 1.2 2006/12/13 22:55:22 vapier Exp $ */ 34#include "tag_report.h" 35#include "debug.h" 36#include "reporter.h" 37#include "splitstr.h" 38 39static char *worst_case(char *, char *); 40 41/************************************************************************ 42 * Report Generation * 43 ************************************************************************/ 44 45/* 46 * printf format statement for standard reports 47 * 5 fields with max/min widths 48 */ 49#define FORMAT "%-20.20s %-15.15s %10.10s %-20.20s %s\n" 50 51/* 52 * This is the central results reporting function. All standard report 53 * format results are printed thru test_result. 54 */ 55int test_result(tag, tcid, tc, result, tags) 56char *tag, *tcid, *tc; 57char *result; 58SYM tags; 59{ 60 char *expert, expkey[KEYSIZE]; 61 register char *c; 62 char **cont; 63 const char **cont_save; 64 65 if (tcid == NULL) 66 tcid = "-"; 67 if (tc == NULL) 68 tc = "-"; 69 if (tag == NULL) 70 tag = "test_result: no tag"; 71 if (result == NULL) 72 result = "(RESULT IS NULL)"; 73 74 strcpy(expkey, "contacts"); 75 /* note: the sym_get here does _not_ change the "cursor" */ 76 if ((expert = (char *)sym_get(tags, expkey)) == NULL) { 77 expert = "UNKNOWN"; 78 } 79 80 /* ' tr " " "_" ' */ 81 for (c = result; *c; c++) { 82 if (*c == ' ') { 83 *c = '_'; 84 } 85 } 86 if (*result == '\0') 87 result = "?"; 88 89 /* split contacts on "," and print out a line for each */ 90 cont_save = splitstr(expert, ",", NULL); 91 for (cont = (char **)cont_save; *cont != NULL; cont++) { 92 printf(FORMAT, tag, tcid, tc, result, *cont); 93 } 94 splitstr_free(cont_save); 95 96 return 0; 97} 98 99/* 100 * CUTS test reporting. 101 * 102 * (1) make a list (2d char array) of all TCIDs (see above for why) 103 * (2) look thru the list: 104 * (a) keep track of the "worst case" in this *TAG* 105 * (b) report each testcase's results 106 * (c) if the testcase number is != 0, count it 107 * (3) report tag's results 108 * (4) check the number of expected results with the actual results, 109 * report an error if they don't match. 110 */ 111 112int cuts_report(tags, keys, at, tag) 113SYM tags, keys; 114char *at, *tag; 115{ 116 DBT Key, Data; 117 118 /* analysis type: count of CUTS test cases */ 119 const char **ant; 120 char *dat; /* strdup(at) */ 121 int tccount; /* expected count of testcases */ 122 int tcnum; /* seen count of testcases */ 123 124 /* a list of tcids */ 125 char **taglist, **tl; 126 int ntags, tagcount; 127 128 char key_get[255]; 129 130 char *result = "", *worst_case(); /* overall result */ 131 132 /* parse analysis type: cuts:tc-count */ 133 ant = splitstr((dat = strdup(at)), ":", NULL); 134 if (ant[1] != NULL) 135 tccount = atoi(ant[1]); 136 else 137 tccount = 0; 138 free(dat); 139 splitstr_free(ant); 140 141 /* extract tcids */ 142 ntags = NTCID_START; 143 taglist = (char **)malloc(sizeof(char *) * ntags); 144 tagcount = 0; 145 146 tl = taglist; 147 sym_seq(tags, &Key, &Data, R_FIRST); 148 do { 149 if (tagcount == ntags) { 150 /* exceeded tag array size -- realloc */ 151 ntags += NTCID_START; 152 taglist = 153 (char **)realloc(taglist, sizeof(char *) * ntags); 154 tl = taglist + tagcount; 155 } 156 157 if (strcmp((char *)Key.data, "_keys") == 0) 158 continue; 159 DEBUG(D_REPORT, 10) 160 printf("cuts_report: tcid %s\n", (char *)Key.data); 161 *tl++ = Key.data; 162 tagcount++; 163 } while (sym_seq(tags, &Key, &Data, R_NEXT) == 0); 164 165 if (tagcount == ntags) { 166 /* exceeded tag array size -- realloc */ 167 ntags++; /* need just one more */ 168 taglist = (char **)realloc(taglist, sizeof(char *) * ntags); 169 tl = taglist + tagcount; 170 } 171 172 *tl++ = NULL; 173 174 ntags = tagcount; 175 176 /* dump all found records */ 177 tcnum = 0; 178 for (tl = taglist; *tl != NULL; tl++) { 179 180 strcpy(key_get, *tl); 181 Key.data = (void *)key_get; 182 183 /*sym_dump_s(sym_get(tags, key_get), 0); */ 184 185 sym_seq(tags, &Key, &Data, R_CURSOR); 186 do { 187 DEBUG(D_REPORT, 10) 188 printf("cuts_report: tc %s = %s\n", 189 (char *)Key.data, (char *)Data.data); 190 result = worst_case(result, (char *)Data.data); 191 test_result(tag, *tl, (char *)Key.data, 192 (char *)Data.data, keys); 193 if (atoi((char *)Key.data)) 194 tcnum++; 195 } while (sym_seq(tags, &Key, &Data, R_NEXT) == 0); 196 } 197 198 test_result(tag, "*", "*", result, keys); 199 200 if (tccount != 0 && tccount != tcnum) 201 test_result(tag, "-", "-", "TC count wrong", keys); 202 203 free(taglist); 204 205 return 0; 206} 207 208/* 209 * Do the report generation. 210 * 211 * A problem: I really need multiple cursors. I'd rather not look into 212 * the depths of the current symbol table implimentation (there are the 213 * cursors there that I could use) so that a different (faster!) symbol 214 * table can be used in the future. 215 * 216 * I could get a key (tag), get it's sub-keys (TCIDs), then get the key 217 * again to reset to the top level, _then_ get the next key. That would 218 * be very inefficient. 219 * 220 * The solution I chose is to extract all tags into a list (char array), 221 * then go thru that list with the cursor free for other levels to use. 222 * 223 * (1) make a list (2d char array) of all Tags 224 * (2) search for the first tag that has a "stime" record, and use that as 225 * the date (MMDDYY) that the tests were run. 226 * (3) print the report header 227 * (4) go thru all tags and report each as described at the beginning of 228 * this file 229 */ 230int tag_report(alltags, ctag, keys) 231SYM alltags, ctag, keys; 232{ 233 234 extern int extended; 235 236 char key_get[KEYSIZE]; 237 char *info; 238 239 /* retrieved _keys values: initation status, start time, duration, 240 * termination type, termination id, start line, end line. */ 241 char *tag, *contact, *is, *mystime, *duration, *tt, *ti, *sl, *el; 242 243 /* Check all driver-level status first */ 244 strcpy(key_get, "tag"); 245 if ((tag = (char *)sym_get(keys, key_get)) == NULL) { 246 return -1; 247 } 248 249 /* Check all driver-level status first */ 250 strcpy(key_get, "initiation_status"); 251 if ((is = (char *)sym_get(keys, key_get)) == NULL) { 252 test_result(tag, NULL, NULL, "no init status", keys); 253 return -1; 254 } 255 256 if (strcmp(is, "ok")) { 257 test_result(tag, NULL, NULL, is, keys); 258 } else { 259 260 strcpy(key_get, "corefile"); 261 if ((info = (char *)sym_get(keys, key_get)) != NULL) 262 if (strcmp(info, "no") != 0) { 263 test_result(tag, NULL, NULL, "coredump", keys); 264 } 265 266 strcpy(key_get, "termination_type"); 267 if ((tt = (char *)sym_get(keys, key_get)) == NULL) { 268 test_result(tag, NULL, NULL, "no Term Type", keys); 269 return -1; 270 } 271 272 if (strcmp(tt, "exited")) { 273 test_result(tag, NULL, NULL, tt, keys); 274 } 275 276 strcpy(key_get, "analysis"); 277 if ((info = (char *)sym_get(keys, key_get)) == NULL) { 278 test_result(tag, NULL, NULL, "no Analysis Type", keys); 279 return -1; 280 } 281 282 /* Getting here indicates that there were no fatal driver-level 283 * errors. Do the kind of reporting requested by the test. 284 */ 285 286 if (strncmp(info, "none", 4) == 0) { 287 /* 288 * If analysis is 'none', alway report the test as 289 * a pass regardless of output or exit status. 290 */ 291 test_result(tag, NULL, NULL, "pass", keys); 292 293 } else if (strncmp(info, "cuts", 4)) { 294 295 /* 296 * If analysis is not cuts, assume it is 'exit', thus 297 * the termination_id is used to determine pass/fail result. 298 */ 299 if (strcmp(tt, "timeout")) { 300 strcpy(key_get, "termination_id"); 301 if ((info = 302 (char *)sym_get(keys, key_get)) == NULL) { 303 test_result(tag, NULL, NULL, 304 "no_Term_Id", keys); 305 } else { 306 if (strcmp(info, "0")) { 307 test_result(tag, NULL, NULL, 308 "fail", keys); 309 } else { 310 test_result(tag, NULL, NULL, 311 "pass", keys); 312 } 313 } 314 } 315 } else { 316 cuts_report(ctag, keys, info, tag); 317 } 318 } 319 320 /* 321 * Extended Format: 322 * - tcid+tc = "!" 323 * - tab separated fields 324 * - no field widths 325 * - fields 6 - ~ are: 326 * start-time (time_t) 327 * duration 328 * termination_id 329 * termination_type 330 * Start Line (of test results in output file) 331 * End Line 332 */ 333 334 if (extended) { 335 336 strcpy(key_get, "termination_id"); 337 if ((ti = (char *)sym_get(keys, key_get)) == NULL) { 338 ti = "No_Termination_ID"; 339 } 340 341 strcpy(key_get, "termination_type"); 342 if ((tt = (char *)sym_get(keys, key_get)) == NULL) { 343 tt = "No_Termination_Type"; 344 } 345 346 strcpy(key_get, "duration"); 347 if ((duration = (char *)sym_get(keys, key_get)) == NULL) { 348 duration = "No_Duration"; 349 } 350 351 strcpy(key_get, "_Start_line"); 352 if ((sl = (char *)sym_get(keys, key_get)) == NULL) { 353 sl = "No_Start_line"; 354 } 355 356 strcpy(key_get, "_End_line"); 357 if ((el = (char *)sym_get(keys, key_get)) == NULL) { 358 el = "No_End_line"; 359 } 360 361 strcpy(key_get, "contacts"); 362 if ((contact = (char *)sym_get(keys, key_get)) == NULL) { 363 contact = "No_Contacts"; 364 } 365 366 strcpy(key_get, "stime"); 367 if ((mystime = (char *)sym_get(keys, key_get)) == NULL) { 368 mystime = "No_stime"; 369 } 370 371 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", 372 tag, "!", "!", is, contact, mystime, duration, 373 ti, tt, sl, el); 374 } 375 376 return 0; 377} 378 379/* 380 * Print a header made up of the RTS keywords 381 * In "extended" mode, print the header to stderr. 382 */ 383int print_header(tags) 384SYM tags; 385{ 386 DBT Key, Data; 387 char key_get[255]; 388 389 FILE *out; 390 391 extern int extended; 392 393 if (extended) 394 out = stderr; 395 else 396 out = stdout; 397 398 fprintf(out, "System Configuration:\n"); 399 /* build header out of RTS keywords */ 400 sprintf(key_get, "_RTS"); 401 Key.data = (void *)key_get; 402 if (sym_seq(tags, &Key, &Data, R_CURSOR) == 0) { 403 do { 404 if (strcmp((char *)Key.data, "PATH") == 0) 405 continue; 406 fprintf(out, "%-20.20s %s\n", (char *)Key.data, 407 (char *)Data.data); 408 } while (sym_seq(tags, &Key, &Data, R_NEXT) == 0); 409 } 410 411 fprintf(out, "\n"); 412 fprintf(out, FORMAT, "tag", "tcid", "testcase", "status", "contact"); 413 fprintf(out, 414 "-------------------------------------------------------------------------------\n"); 415 416 return 0; 417} 418 419/* 420 * CUTS testcase record 421 * 422 * This is passed s SYM for the current tag and the initiation keys. 423 * The text seen by lex is in yytext (global). 424 */ 425int cuts_testcase(tag, keys) 426SYM tag, keys; 427{ 428 char *cuts_info[5]; 429 char key[KEYSIZE]; 430 char *oldresult, *newresult, *worst_case(); 431 int tok_num = 0; 432 extern char yytext[]; 433 434 cuts_info[tok_num] = strtok(yytext, "\t "); 435 while (tok_num < 5 && 436 (cuts_info[++tok_num] = strtok(NULL, "\t ")) != NULL) ; 437 438 strcpy(key, cuts_info[0]); 439 strcat(key, ","); 440 strcat(key, cuts_info[1]); 441 442#ifdef DEBUGGING 443 DEBUG(D_SCAN_CUTS, 1) { 444 printf("cuts_testcase: TCID=%s TC=%s Result=%s\n", cuts_info[0], 445 cuts_info[1], cuts_info[2]); 446 printf("cuts_testcase: %d %s\n", tok_num, key); 447 } 448#endif 449 450 if ((oldresult = (char *)sym_get(tag, key)) != NULL) { 451 /* Duplicate -- assume mulitple runs */ 452 /* keep "worst case" */ 453 newresult = worst_case(oldresult, cuts_info[2]); 454 sym_put(tag, key, strdup(newresult), PUT_REPLACE); 455 free(oldresult); /* remove the "data" portion of the key */ 456 } else { 457 sym_put(tag, key, strdup(cuts_info[2]), 0); 458 } 459 return 0; 460} 461 462/* 463 * Determine a "worst case" status from two given statuses. 464 */ 465static char *worst_case(t1, t2) 466char *t1, *t2; 467{ 468 /* NULL-terminated table, ordered from worst-case to best-case */ 469 static char *worst[] = { 470 "FAIL", "BROK", "PASS", "CONF", 471 "WARN", "INFO", NULL, 472 }; 473 474 char **w1, **w2; 475 476 /* Search the table for each status, then use the index to determine 477 which has a lower precedence */ 478 for (w1 = worst; *w1 != NULL && strcmp(t1, *w1); w1++) ; 479 480 for (w2 = worst; *w2 != NULL && strcmp(t2, *w2); w2++) ; 481 482 if (w1 < w2) 483 return (t1); 484 else 485 return (t2); 486 487} 488