Stop verifying ResultWriter.write_results exit codes
[functest-xtesting.git] / xtesting / core / robotframework.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2017 Orange and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 """Define classes required to run any Robot suites."""
11
12 from __future__ import division
13
14 import errno
15 import logging
16 import os
17
18 import robot.api
19 from robot.errors import RobotError
20 from robot.reporting import resultwriter
21 import robot.run
22 from robot.utils.robottime import timestamp_to_secs
23 from six import StringIO
24
25 from xtesting.core import testcase
26
27 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
28
29
30 class ResultVisitor(robot.api.ResultVisitor):
31     """Visitor to get result details."""
32
33     def __init__(self):
34         self._data = []
35
36     def visit_test(self, test):
37         output = {}
38         output['name'] = test.name
39         output['parent'] = test.parent.name
40         output['status'] = test.status
41         output['starttime'] = test.starttime
42         output['endtime'] = test.endtime
43         output['critical'] = test.critical
44         output['text'] = test.message
45         output['elapsedtime'] = test.elapsedtime
46         self._data.append(output)
47
48     def get_data(self):
49         """Get the details of the result."""
50         return self._data
51
52
53 class RobotFramework(testcase.TestCase):
54     """RobotFramework runner."""
55
56     __logger = logging.getLogger(__name__)
57     dir_results = "/var/lib/xtesting/results"
58
59     def __init__(self, **kwargs):
60         super(RobotFramework, self).__init__(**kwargs)
61         self.res_dir = os.path.join(self.dir_results, self.case_name)
62         self.xml_file = os.path.join(self.res_dir, 'output.xml')
63
64     def parse_results(self):
65         """Parse output.xml and get the details in it."""
66         result = robot.api.ExecutionResult(self.xml_file)
67         visitor = ResultVisitor()
68         result.visit(visitor)
69         try:
70             self.result = 100 * (
71                 result.suite.statistics.critical.passed /
72                 result.suite.statistics.critical.total)
73         except ZeroDivisionError:
74             self.__logger.error("No test has been run")
75         self.start_time = timestamp_to_secs(result.suite.starttime)
76         self.stop_time = timestamp_to_secs(result.suite.endtime)
77         self.details = {}
78         self.details['description'] = result.suite.name
79         self.details['tests'] = visitor.get_data()
80
81     def generate_report(self):
82         """Generate html and xunit outputs"""
83         result = robot.api.ExecutionResult(self.xml_file)
84         writer = resultwriter.ResultWriter(result)
85         return writer.write_results(
86             report='{}/report.html'.format(self.res_dir),
87             log='{}/log.html'.format(self.res_dir),
88             xunit='{}/xunit.xml'.format(self.res_dir))
89
90     def run(self, **kwargs):
91         """Run the RobotFramework suites
92
93         Here are the steps:
94            * create the output directories if required,
95            * get the results in output.xml,
96            * delete temporary files.
97
98         Args:
99             kwargs: Arbitrary keyword arguments.
100
101         Returns:
102             EX_OK if all suites ran well.
103             EX_RUN_ERROR otherwise.
104         """
105         try:
106             suites = kwargs["suites"]
107             variable = kwargs.get("variable", [])
108             variablefile = kwargs.get("variablefile", [])
109             include = kwargs.get("include", [])
110         except KeyError:
111             self.__logger.exception("Mandatory args were not passed")
112             return self.EX_RUN_ERROR
113         try:
114             os.makedirs(self.res_dir)
115         except OSError as ex:
116             if ex.errno != errno.EEXIST:
117                 self.__logger.exception("Cannot create %s", self.res_dir)
118                 return self.EX_RUN_ERROR
119         except Exception:  # pylint: disable=broad-except
120             self.__logger.exception("Cannot create %s", self.res_dir)
121             return self.EX_RUN_ERROR
122         stream = StringIO()
123         robot.run(*suites, variable=variable, variablefile=variablefile,
124                   include=include, output=self.xml_file, log='NONE',
125                   report='NONE', stdout=stream)
126         self.__logger.info("\n%s", stream.getvalue())
127         try:
128             self.parse_results()
129             self.__logger.info("Results were successfully parsed")
130             self.generate_report()
131             self.__logger.info("Results were successfully generated")
132         except RobotError as ex:
133             self.__logger.error("Run suites before publishing: %s", ex.message)
134             return self.EX_RUN_ERROR
135         except Exception:  # pylint: disable=broad-except
136             self.__logger.exception("Cannot parse results")
137             return self.EX_RUN_ERROR
138         return self.EX_OK