Initial commit.
[qa-tools:testrunner-lite.git] / src / testresultlogger.c
1 /*
2  * This file is part of testrunner-lite
3  *
4  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5  *
6  * Contact: Sampo Saaristo <ext-sampo.2.saaristo@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * version 2.1 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 /* ------------------------------------------------------------------------- */
25 /* INCLUDE FILES */
26 #include <time.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <libxml/xmlwriter.h>
31 #include "testresultlogger.h"
32 #include "log.h"
33
34 /* ------------------------------------------------------------------------- */
35 /* EXTERNAL DATA STRUCTURES */
36 /* None */
37
38 /* ------------------------------------------------------------------------- */
39 /* EXTERNAL GLOBAL VARIABLES */
40 /* None */
41
42 /* ------------------------------------------------------------------------- */
43 /* EXTERNAL FUNCTION PROTOTYPES */
44 /* None */
45
46 /* ------------------------------------------------------------------------- */
47 /* GLOBAL VARIABLES */
48 /* None */
49
50 /* ------------------------------------------------------------------------- */
51 /* CONSTANTS */
52 /* None */
53
54 /* ------------------------------------------------------------------------- */
55 /* MACROS */
56 /* None */
57
58 /* ------------------------------------------------------------------------- */
59 /* LOCAL GLOBAL VARIABLES */
60 LOCAL xmlTextWriterPtr writer;
61 LOCAL FILE *ofile;
62 /* ------------------------------------------------------------------------- */
63 /* LOCAL CONSTANTS AND MACROS */
64 /* None */
65
66 /* ------------------------------------------------------------------------- */
67 /* MODULE DATA STRUCTURES */
68 struct  
69 {
70     int (*write_pre_suite_tag) (td_suite *);
71     int (*write_post_suite_tag) (void);
72     int (*write_pre_set_tag) (td_set *);
73     int (*write_post_set_tag) (td_set *);
74 } out_cbs;
75 /* ------------------------------------------------------------------------- */
76 /* LOCAL FUNCTION PROTOTYPES */
77 /* ------------------------------------------------------------------------- */
78 LOCAL int xml_write_pre_suite_tag (td_suite *);
79 /* ------------------------------------------------------------------------- */
80 LOCAL int xml_write_pre_set_tag (td_set *);
81 /* ------------------------------------------------------------------------- */
82 LOCAL int xml_write_step (const void *, const void *);
83 /* ------------------------------------------------------------------------- */
84 LOCAL int xml_write_case (const void *, const void *);
85 /* ------------------------------------------------------------------------- */
86 LOCAL int xml_write_post_set_tag (td_set *);
87 /* ------------------------------------------------------------------------- */
88 LOCAL int txt_write_pre_suite_tag (td_suite *);
89 /* ------------------------------------------------------------------------- */
90 LOCAL int txt_write_post_suite_tag ();
91 /* ------------------------------------------------------------------------- */
92 LOCAL int txt_write_pre_set_tag (td_set *);
93 /* ------------------------------------------------------------------------- */
94 LOCAL int txt_write_post_set_tag (td_set *);
95 /* ------------------------------------------------------------------------- */
96 LOCAL int txt_write_case (const void *, const void *);
97 /* ------------------------------------------------------------------------- */
98 /* FORWARD DECLARATIONS */
99 /* None */
100
101 /* ------------------------------------------------------------------------- */
102 /* ==================== LOCAL FUNCTIONS ==================================== */
103 /* ------------------------------------------------------------------------- */
104 /* ------------------------------------------------------------------------- */
105 /************************** xml output ***************************************/
106 /* ------------------------------------------------------------------------- */
107 /** Write suite start xml tag
108  * @param suite suite data
109  * @return 0 on success, 1 on error
110  */
111 LOCAL int xml_write_pre_suite_tag (td_suite *suite)
112 {
113         
114         if (xmlTextWriterStartElement (writer, BAD_CAST "suite") < 0)
115                 goto err_out;
116         
117         if (xmlTextWriterWriteAttribute (writer,  BAD_CAST "name", 
118                                          suite->gen.name) < 0)
119                 goto err_out;
120         return 0;
121 err_out:
122         return 1;
123 }
124 /* ------------------------------------------------------------------------- */
125 /** Write pre-set xml tag
126  * @param set set data
127  * @return 0 on success, 1 on error
128  */
129 LOCAL int xml_write_pre_set_tag (td_set *set)
130 {
131         if (xmlTextWriterStartElement (writer, BAD_CAST "set") < 0)
132                 goto err_out;
133         
134         if (xmlTextWriterWriteAttribute (writer, 
135                                          BAD_CAST "name", 
136                                          set->gen.name) < 0)
137                 goto err_out;
138         
139         if (set->gen.description)
140                 if (xmlTextWriterWriteAttribute (writer, 
141                                                  BAD_CAST "description", 
142                                                  set->gen.description) < 0)
143                         goto err_out;
144         
145         if (set->environment)
146                 if (xmlTextWriterWriteAttribute (writer, 
147                                                  BAD_CAST "environment", 
148                                                  set->environment) < 0)
149                         goto err_out;
150         return 0;
151  err_out:
152         return 1;
153 }
154 /* ------------------------------------------------------------------------- */
155 /** Write step result xml
156  * @param data step data 
157  * @param user not used
158  * @return 1 on success, 0 on error if the step is failed
159  */
160 LOCAL int xml_write_step (const void *data, const void *user)
161 {
162         td_step *step = (td_step *)data;
163         struct tm *tm;
164
165         if (xmlTextWriterStartElement (writer, BAD_CAST "step") < 0)
166                 goto err_out;
167
168         if (xmlTextWriterWriteAttribute (writer, 
169                                          BAD_CAST "command", 
170                                          step->step) < 0)
171                 goto err_out;
172         
173         if (step->has_result == 0) {
174                 if (xmlTextWriterWriteAttribute (writer, 
175                                                  BAD_CAST "result", 
176                                                  BAD_CAST "N/A") < 0)
177                         goto err_out;
178
179
180         } else if (xmlTextWriterWriteAttribute (writer, 
181                                                 BAD_CAST "result", 
182                                                 step->expected_result == 
183                                                 step->return_code ? 
184                                                 BAD_CAST "PASS" :
185                                                 BAD_CAST "FAIL") < 0)
186                 goto err_out;
187         
188         if (step->failure_info) {
189                 if (xmlTextWriterWriteAttribute (writer, 
190                                                  BAD_CAST "failure_info", 
191                                                  step->failure_info) < 0)
192                         goto err_out;
193         }
194
195         if (xmlTextWriterWriteFormatElement (writer,
196                                              BAD_CAST "expected_result",
197                                              "%d", step->expected_result) < 0)
198                 goto err_out;
199         
200         if (xmlTextWriterWriteFormatElement (writer,
201                                              BAD_CAST "return_code",
202                                              "%d", step->return_code) < 0)
203                 goto err_out;
204         
205         tm =  localtime (&step->start);
206         if (xmlTextWriterWriteFormatElement (writer,
207                                              BAD_CAST "start",
208                                              "%02d-%02d-%02d %02d:%02d:%02d", 
209                                              tm->tm_year+1900,
210                                              tm->tm_mon+1,
211                                              tm->tm_mday,
212                                              tm->tm_hour,
213                                              tm->tm_min,
214                                              tm->tm_sec) < 0)
215                 goto err_out;
216
217         tm =  localtime (&step->end);
218         if (xmlTextWriterWriteFormatElement (writer,
219                                              BAD_CAST "end",
220                                              "%02d-%02d-%02d %02d:%02d:%02d", 
221                                              tm->tm_year+1900,
222                                              tm->tm_mon+1,
223                                              tm->tm_mday,
224                                              tm->tm_hour,
225                                              tm->tm_min,
226                                              tm->tm_sec) < 0)
227                 goto err_out;
228
229         if (step->stdout_)
230                 if (xmlTextWriterWriteFormatElement (writer,
231                                                      BAD_CAST "stdout",
232                                                      "%s", 
233                                                      step->stdout_) < 0)
234                         goto err_out;
235
236         if (step->stderr_)
237                 if (xmlTextWriterWriteFormatElement (writer,
238                                                      BAD_CAST "stderr",
239                                                      "%s", 
240                                                      step->stderr_) < 0)
241                         goto err_out;
242
243
244         xml_end_element();
245         
246
247         return (step->expected_result == step->return_code);
248         
249 err_out:
250         return 0;
251 }
252 /* ------------------------------------------------------------------------- */
253 /** Write case result xml
254  * @param data case data 
255  * @param user not used
256  * @return 1 on success, 0 on error
257  */
258 LOCAL int xml_write_case (const void *data, const void *user)
259 {
260         td_case *c = (td_case *)data;
261
262         if (c->filtered)
263                 return 1;
264
265         if (xmlTextWriterStartElement (writer, BAD_CAST "case") < 0)
266                 goto err_out;
267
268         if (xmlTextWriterWriteAttribute (writer, 
269                                          BAD_CAST "name", 
270                                          c->gen.name) < 0)
271                 goto err_out;
272         
273         if (c->gen.description)
274                 if (xmlTextWriterWriteAttribute (writer, 
275                                                  BAD_CAST "description", 
276                                                  c->gen.description) < 0)
277                 goto err_out;
278
279         if (xmlTextWriterWriteAttribute (writer, 
280                                          BAD_CAST "manual", 
281                                          BAD_CAST (c->gen.manual ? "true" :
282                                                    "false")) < 0)
283                 goto err_out;
284
285         if (xmlTextWriterWriteAttribute (writer, 
286                                          BAD_CAST "insignificant", 
287                                          BAD_CAST (c->gen.insignificant ? 
288                                                    "true" :
289                                                    "false")) < 0)
290                 goto err_out;
291
292
293         if (xmlTextWriterWriteAttribute (writer, 
294                                          BAD_CAST "result", 
295                                          BAD_CAST (case_result_str
296                                                    (c->case_res))) < 0)
297                 
298                 goto err_out;
299
300         if (c->subfeature)
301                 if (xmlTextWriterWriteAttribute (writer, 
302                                                  BAD_CAST "subfeature", 
303                                                  c->subfeature) < 0)
304                         goto err_out;
305
306         if (c->gen.requirement)
307                 if (xmlTextWriterWriteAttribute (writer, 
308                                                  BAD_CAST "requirement", 
309                                                  c->gen.requirement) < 0)
310                         goto err_out;
311
312         if (c->gen.level)
313                 if (xmlTextWriterWriteAttribute (writer, 
314                                                  BAD_CAST "level", 
315                                                  c->gen.level) < 0)
316                         goto err_out;
317
318         if (c->gen.manual && c->comment)
319                 if (xmlTextWriterWriteAttribute (writer, 
320                                                  BAD_CAST "comment", 
321                                                  c->comment) < 0)
322                         goto err_out;
323
324
325         xmlListWalk (c->steps, xml_write_step, NULL);
326
327         xml_end_element ();
328
329         return 1;
330
331 err_out:
332         LOG_MSG (LOG_ERR, "%s:%s: error\n", PROGNAME, __FUNCTION__);
333         
334         return 0;
335 }
336 /* ------------------------------------------------------------------------- */
337 /** Write set start tag and cases result xml
338  * @param set set data
339  * @return 0 on success, 1 on error
340  */
341 LOCAL int xml_write_post_set_tag (td_set *set)
342 {
343         
344         
345         xmlListWalk (set->cases, xml_write_case, NULL);
346         
347         return 0;
348 }
349 /* ------------------------------------------------------------------------- */
350 /************************* text output ***************************************/
351 /* ------------------------------------------------------------------------- */
352 /** Write step result to text file
353  * @param data step data 
354  * @param user not used
355  * @return 1 on success, 0 on error
356  */
357 LOCAL int txt_write_step (const void *data, const void *user)
358 {
359         td_step *step = (td_step *)data;
360         struct tm *tm;
361         fprintf (ofile, "----------------------------------"
362                  "----------------------------------\n");
363         fprintf (ofile, "      Test step       : %s\n", step->step);
364         tm =  localtime (&step->start);
365
366         fprintf (ofile, "        start         : %02d-%02d-%02d"
367                  " %02d:%02d:%02d\n",
368                  tm->tm_year+1900,
369                  tm->tm_mon+1,
370                  tm->tm_mday,
371                  tm->tm_hour,
372                  tm->tm_min,
373                  tm->tm_sec);
374         tm =  localtime (&step->end);
375         fprintf (ofile, "        end           : %02d-%02d-%02d"
376                  " %02d:%02d:%02d\n",
377                  tm->tm_year+1900,
378                  tm->tm_mon+1,
379                  tm->tm_mday,
380                  tm->tm_hour,
381                  tm->tm_min,
382                  tm->tm_sec);
383         fprintf (ofile, "        expected code : %d\n", step->expected_result);
384         fprintf (ofile, "        return code   : %d\n", step->return_code);
385         fprintf (ofile, "        result        : %s %s\n",
386                  (step->return_code == step->expected_result ? "PASS" : "FAIL"),
387                  (step->failure_info ? (char *)step->failure_info : " "));
388         fprintf (ofile, "        stdout        : %s\n",
389                  step->stdout_ ? (char *)step->stdout_ : " ");
390         fprintf (ofile, "        stderr        : %s\n",
391                  step->stderr_ ? (char *)step->stderr_ : " ");
392         fflush (ofile);
393
394         return (step->expected_result == step->return_code);
395 }
396 /* ------------------------------------------------------------------------- */
397 /** Write case result to text file
398  * @param data case data 
399  * @param user not used
400  * @return 1 on success, 0 on error
401  */
402 LOCAL int txt_write_case (const void *data, const void *user)
403 {
404         td_case *c = (td_case *)data;
405         
406         if (c->filtered)
407                 return 1;
408
409         fprintf (ofile, "----------------------------------"
410                  "----------------------------------\n");
411         fprintf (ofile, "    Test case name  : %s\n", c->gen.name);
412         fprintf (ofile, "      description   : %s\n", c->gen.description ? 
413                  (char *)c->gen.description : "");
414         fprintf (ofile, "      manual        : %s\n", c->gen.manual ?
415                  "true" : "false");
416         
417         if (c->gen.requirement)
418             fprintf (ofile, "      requirement   : %s\n", c->gen.requirement);
419         if (c->subfeature)
420             fprintf (ofile, "      subfeature    : %s\n", c->subfeature);
421 #if 0
422         if (c->gen.type)
423             fprintf (ofile, "      type          : %s\n", c->gen.type);
424 #endif
425         if (c->gen.level)
426             fprintf (ofile, "      level         : %s\n", c->gen.level);
427         
428         fprintf (ofile, "      insignificant : %s\n", c->gen.insignificant ?
429                  "true" : "false");
430         
431         
432         if (c->gen.manual && c->comment)
433                 fprintf (ofile, "      comment       : %s\n", c->comment);
434                 
435         fflush (ofile);
436         
437         xmlListWalk (c->steps, txt_write_step, NULL);
438
439
440         return 1;
441 }
442 /** Write suite start txt tag
443  * @param suite suite data
444  * @return 0 on success, 1 on error
445  */
446 LOCAL int txt_write_pre_suite_tag (td_suite *suite)
447 {
448         fprintf (ofile, "----------------------------------"
449                  "----------------------------------\n");
450
451         fprintf (ofile, "Test suite name : %s\n", suite->gen.name);
452         fprintf (ofile, "  description   : %s\n", suite->gen.description ? 
453                  (char *)suite->gen.description : " ");
454         if (suite->domain)
455                 fprintf (ofile, "  domain        : %s\n", suite->domain);
456         
457         fflush (ofile);
458         
459         return 0;
460 }
461 /* ------------------------------------------------------------------------- */
462 /** Write post suite to text file - does not do anything at the moment
463  * @return 0 on always
464  */
465 LOCAL int txt_write_post_suite_tag ()
466 {
467         return 0;
468
469 }
470 /* ------------------------------------------------------------------------- */
471 /** Write pre set information to text file
472  * @param set set data
473  * @return 0 on always
474  */
475 LOCAL int txt_write_pre_set_tag (td_set *set)
476 {
477         fprintf (ofile, "----------------------------------"
478                  "----------------------------------\n");
479
480         fprintf (ofile, "  Test set name   : %s\n", set->gen.name);
481         fprintf (ofile, "    description   : %s\n", set->gen.description ? 
482                  (char *)set->gen.description : "");
483         if (set->feature)
484                 fprintf (ofile, "    feature       : %s\n", set->feature);
485         
486         fprintf (ofile, "    environment   : %s\n", set->environment ? 
487                  (char *)set->environment : "");
488
489         fflush (ofile);
490         return 0;
491
492 }
493 /* ------------------------------------------------------------------------- */
494 /** Write post set information to text file - loop through test cases
495  * @param set set data
496  * @return 0 on always
497  */
498 LOCAL int txt_write_post_set_tag (td_set *set)
499 {
500         
501         xmlListWalk (set->cases, txt_write_case, NULL);
502         fflush (ofile);
503         
504         return 0;
505 }
506 /* ------------------------------------------------------------------------- */
507 /* ======================== FUNCTIONS ====================================== */
508 /* ------------------------------------------------------------------------- */
509 /** Initialize result logger according to user options.
510  *  @param opts commandline options 
511  *  @param hwinfo hardware information
512  *  @return 0 on success
513  */
514 int init_result_logger (testrunner_lite_options *opts, hw_info *hwinfo)
515 {
516
517     switch (opts->output_type) {
518     case OUTPUT_TYPE_XML:
519             /*
520              * Instantiate writer 
521              */
522             writer = xmlNewTextWriterFilename(opts->output_filename, 0);
523             if (!writer)  {
524                     LOG_MSG (LOG_ERR, "%s:%s:failed to create writer for %s\n",
525                              PROGNAME, __FUNCTION__, opts->output_filename);
526                     return 1;
527             }
528             xmlTextWriterSetIndent (writer, 1);
529             if (xmlTextWriterStartDocument(writer, 
530                                            "1.0", 
531                                            "UTF-8", 
532                                            NULL) < 0) {
533                     LOG_MSG (LOG_ERR, "%s:%s:failed to write document start\n",
534                              PROGNAME, __FUNCTION__);
535                     return 1;
536             }
537                     
538             if (xmlTextWriterStartElement (writer, BAD_CAST "testresults") 
539                 < 0) {
540                     LOG_MSG (LOG_ERR, "%s:%s:failed to write testsresults tag\n",
541                              PROGNAME, __FUNCTION__);
542                     return 1;
543             }
544             if (xmlTextWriterWriteAttribute (writer, 
545                                              BAD_CAST "version", 
546                                              BAD_CAST "1.0") < 0)
547                     return 1;
548
549             if (xmlTextWriterWriteAttribute (writer, 
550                                              BAD_CAST "environment", 
551                                              BAD_CAST (opts->environment ?
552                                                        opts->environment :
553                                                        "unknown")) < 0)
554                     return 1;
555
556             
557             if (xmlTextWriterWriteAttribute (writer, 
558                                              BAD_CAST "hwproduct", 
559                                              (hwinfo->product ?
560                                               hwinfo->product :
561                                               BAD_CAST "unknown")) < 0)
562                     return 1;
563
564
565             
566             if (xmlTextWriterWriteAttribute (writer, 
567                                              BAD_CAST "hwbuild", 
568                                              (hwinfo->hw_build ?
569                                               hwinfo->hw_build :
570                                               BAD_CAST "unknown")) < 0)
571                     return 1;
572
573
574             /*
575              * Set callbacks
576              */
577             out_cbs.write_pre_suite_tag = xml_write_pre_suite_tag;
578             out_cbs.write_post_suite_tag = xml_end_element;
579             out_cbs.write_pre_set_tag = xml_write_pre_set_tag;
580             out_cbs.write_post_set_tag = xml_write_post_set_tag;
581              
582             
583             break;
584             
585     case OUTPUT_TYPE_TXT:
586             /*
587              * Open results file
588              */
589             ofile = fopen (opts->output_filename, "w+");
590             if (!ofile)  {
591                     LOG_MSG (LOG_ERR, "%s:%s:failed to open file %s %s\n",
592                              PROGNAME, __FUNCTION__, opts->output_filename,
593                              strerror(errno));
594                     return 1;
595             }
596             fprintf (ofile,"Test results:\n");
597             fprintf (ofile, "  environment : %s\n", opts->environment);
598
599             fprintf (ofile, "  hwproduct   : %s\n", 
600                      (char *)(hwinfo->product ? hwinfo->product : 
601                               (unsigned char *)"unknown"));
602             
603             fprintf (ofile, "  hwbuild     : %s\n", 
604                      (char *)(hwinfo->hw_build ? hwinfo->hw_build :
605                               (unsigned char *)"unknown"));
606             
607
608             /*
609              * Set callbacks
610              */
611             out_cbs.write_pre_suite_tag = txt_write_pre_suite_tag;
612             out_cbs.write_post_suite_tag = txt_write_post_suite_tag;
613             out_cbs.write_pre_set_tag = txt_write_pre_set_tag;
614             out_cbs.write_post_set_tag = txt_write_post_set_tag;
615              
616             break;
617
618     default:
619             LOG_MSG (LOG_ERR, "%s:%s:invalid output type %d\n",
620                      PROGNAME, __FUNCTION__, opts->output_type);
621             return 1;
622     }
623     
624     return 0;
625 }
626 /* ------------------------------------------------------------------------- */
627 /** Call pre_suite_tag callback
628  *  @param suite suite data
629  *  @return 0 on success
630  */
631 int write_pre_suite_tag (td_suite *suite)
632 {
633         return out_cbs.write_pre_suite_tag (suite);
634 }
635 /* ------------------------------------------------------------------------- */
636 /** Call post_suite_tag callback
637  *  @param suite suite data
638  *  @return 0 on success
639  */
640 int write_post_suite_tag (td_suite *suite)
641 {
642         
643         return out_cbs.write_post_suite_tag ();
644 }
645 /* ------------------------------------------------------------------------- */
646 /** Call pre_set_tag callback
647  *  @param set set data
648  *  @return 0 on success
649  */
650 int write_pre_set_tag (td_set *set)
651 {
652         return out_cbs.write_pre_set_tag (set);
653 }
654 /* ------------------------------------------------------------------------- */
655 /** Call post_set_tag callback
656  *  @param set set data
657  *  @return 0 on success
658  */
659 int write_post_set_tag (td_set *set)
660 {
661         
662         return out_cbs.write_post_set_tag (set);
663 }
664 /* ------------------------------------------------------------------------- */
665 /** Write end element tag
666  * @return 0 on success, 1 on error.
667  */
668 int xml_end_element ()
669 {
670         
671         if (xmlTextWriterFullEndElement (writer) < 0)
672                 goto err_out;
673         return 0;
674 err_out:
675         return 1;
676 }
677 /* ------------------------------------------------------------------------- */
678 /** Close the result logger */
679
680 void close_result_logger (void)
681 {
682         if (writer) {
683                 xml_end_element(); /* </testresults> */ 
684                 xmlTextWriterFlush (writer);
685                 xmlFreeTextWriter (writer);
686                 writer = NULL;
687         } else if (ofile) {
688                 fprintf (ofile, "----------------------------------"
689                          "----------------------------------\n");
690                 fprintf (ofile, "End of test results.\n");
691                 fflush (ofile);
692                 fclose (ofile);
693                 ofile = NULL;
694         } else {
695                 LOG_MSG (LOG_ERR, "%s:%s: Result logger not open?\n",
696                          PROGNAME, __FUNCTION__);
697         }
698
699         return;
700 }
701 /* ================= OTHER EXPORTED FUNCTIONS ============================== */
702 /* None */
703
704 /* ------------------------------------------------------------------------- */
705 /* End of file */