Adding first patch for behave feature
[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 logging
15 import os
16
17 import robot.api
18 from robot.errors import RobotError
19 from robot.reporting import resultwriter
20 import robot.run
21 from robot.utils.robottime import timestamp_to_secs
22 from six import StringIO
23
24 from xtesting.core import testcase
25
26 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
27
28
29 class ResultVisitor(robot.api.ResultVisitor):
30     """Visitor to get result details."""
31
32     def __init__(self):
33         self._data = []
34
35     def visit_test(self, test):
36         output = {}
37         output['name'] = test.name
38         output['parent'] = test.parent.name
39         output['status'] = test.status
40         output['starttime'] = test.starttime
41         output['endtime'] = test.endtime
42         output['critical'] = test.critical
43         output['text'] = test.message
44         output['elapsedtime'] = test.elapsedtime
45         self._data.append(output)
46
47     def get_data(self):
48         """Get the details of the result."""
49         return self._data
50
51
52 class RobotFramework(testcase.TestCase):
53     """RobotFramework runner."""
54
55     __logger = logging.getLogger(__name__)
56     dir_results = "/var/lib/xtesting/results"
57
58     def __init__(self, **kwargs):
59         super(RobotFramework, self).__init__(**kwargs)
60         self.res_dir = os.path.join(self.dir_results, self.case_name)
61         self.xml_file = os.path.join(self.res_dir, 'output.xml')
62
63     def parse_results(self):
64         """Parse output.xml and get the details in it."""
65         result = robot.api.ExecutionResult(self.xml_file)
66         visitor = ResultVisitor()
67         result.visit(visitor)
68         try:
69             self.result = 100 * (
70                 result.suite.statistics.critical.passed /
71                 result.suite.statistics.critical.total)
72         except ZeroDivisionError:
73             self.__logger.error("No test has been run")
74         self.start_time = timestamp_to_secs(result.suite.starttime)
75         self.stop_time = timestamp_to_secs(result.suite.endtime)
76         self.details = {}
77         self.details['description'] = result.suite.name
78         self.details['tests'] = visitor.get_data()
79
80     def generate_report(self):
81         """Generate html and xunit outputs"""
82         result = robot.api.ExecutionResult(self.xml_file)
83         writer = resultwriter.ResultWriter(result)
84         return writer.write_results(
85             report='{}/report.html'.format(self.res_dir),
86             log='{}/log.html'.format(self.res_dir),
87             xunit='{}/xunit.xml'.format(self.res_dir))
88
89     def run(self, **kwargs):
90         """Run the RobotFramework suites
91
92         Here are the steps:
93            * create the output directories if required,
94            * get the results in output.xml,
95            * delete temporary files.
96
97         Args:
98             kwargs: Arbitrary keyword arguments.
99
100         Returns:
101             EX_OK if all suites ran well.
102             EX_RUN_ERROR otherwise.
103         """
104         try:
105             suites = kwargs["suites"]
106             variable = kwargs.get("variable", [])
107             variablefile = kwargs.get("variablefile", [])
108             include = kwargs.get("include", [])
109         except KeyError:
110             self.__logger.exception("Mandatory args were not passed")
111             return self.EX_RUN_ERROR
112         if not os.path.exists(self.res_dir):
113             try:
114                 os.makedirs(self.res_dir)
115             except Exception:  # pylint: disable=broad-except
116                 self.__logger.exception("Cannot create %s", self.res_dir)
117                 return self.EX_RUN_ERROR
118         stream = StringIO()
119         robot.run(*suites, variable=variable, variablefile=variablefile,
120                   include=include, output=self.xml_file, log='NONE',
121                   report='NONE', stdout=stream)
122         self.__logger.info("\n%s", stream.getvalue())
123         try:
124             self.parse_results()
125             self.__logger.info("Results were successfully parsed")
126             self.generate_report()
127             self.__logger.info("Results were successfully generated")
128         except RobotError as ex:
129             self.__logger.error("Run suites before publishing: %s", ex.message)
130             return self.EX_RUN_ERROR
131         except Exception:  # pylint: disable=broad-except
132             self.__logger.exception("Cannot parse results")
133             return self.EX_RUN_ERROR
134         return self.EX_OK