Add suffixes to OpenStack resource names
[functest.git] / functest / 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 import robot.run
21 from robot.utils.robottime import timestamp_to_secs
22 from six import StringIO
23
24 from functest.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 = "/home/opnfv/functest/results"
57
58     def __init__(self, **kwargs):
59         self.res_dir = os.path.join(self.dir_results, 'robot')
60         self.xml_file = os.path.join(self.res_dir, 'output.xml')
61         super(RobotFramework, self).__init__(**kwargs)
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 run(self, **kwargs):
81         """Run the RobotFramework suites
82
83         Here are the steps:
84            * create the output directories if required,
85            * get the results in output.xml,
86            * delete temporary files.
87
88         Args:
89             kwargs: Arbitrary keyword arguments.
90
91         Returns:
92             EX_OK if all suites ran well.
93             EX_RUN_ERROR otherwise.
94         """
95         try:
96             suites = kwargs["suites"]
97             variable = kwargs.get("variable", [])
98             variablefile = kwargs.get("variablefile", [])
99         except KeyError:
100             self.__logger.exception("Mandatory args were not passed")
101             return self.EX_RUN_ERROR
102         try:
103             os.makedirs(self.res_dir)
104         except OSError as ex:
105             if ex.errno != errno.EEXIST:
106                 self.__logger.exception("Cannot create %s", self.res_dir)
107                 return self.EX_RUN_ERROR
108         except Exception:  # pylint: disable=broad-except
109             self.__logger.exception("Cannot create %s", self.res_dir)
110             return self.EX_RUN_ERROR
111         stream = StringIO()
112         robot.run(*suites, variable=variable, variablefile=variablefile,
113                   output=self.xml_file, log='NONE',
114                   report='NONE', stdout=stream)
115         self.__logger.info("\n" + stream.getvalue())
116         self.__logger.info("Results were successfully generated")
117         try:
118             self.parse_results()
119             self.__logger.info("Results were successfully parsed")
120         except RobotError as ex:
121             self.__logger.error("Run suites before publishing: %s", ex.message)
122             return self.EX_RUN_ERROR
123         except Exception:  # pylint: disable=broad-except
124             self.__logger.exception("Cannot parse results")
125             return self.EX_RUN_ERROR
126         return self.EX_OK