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