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