aboutsummaryrefslogtreecommitdiffstats
path: root/functest/core/robotframework.py
blob: 689d9d9462d6823ba014c6d1e3b63509b6728b86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python

# Copyright (c) 2017 Orange and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0

"""Define classes required to run any Robot suites."""

from __future__ import division

import errno
import logging
import os

import robot.api
from robot.errors import RobotError
import robot.run
from robot.utils.robottime import timestamp_to_secs
from six import StringIO

from functest.core import testcase
from functest.utils import constants

__author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"


class ResultVisitor(robot.api.ResultVisitor):
    """Visitor to get result details."""

    def __init__(self):
        self._data = []

    def visit_test(self, test):
        output = {}
        output['name'] = test.name
        output['parent'] = test.parent.name
        output['status'] = test.status
        output['starttime'] = test.starttime
        output['endtime'] = test.endtime
        output['critical'] = test.critical
        output['text'] = test.message
        output['elapsedtime'] = test.elapsedtime
        self._data.append(output)

    def get_data(self):
        """Get the details of the result."""
        return self._data


class RobotFramework(testcase.TestCase):
    """RobotFramework runner."""

    __logger = logging.getLogger(__name__)

    def __init__(self, **kwargs):
        self.res_dir = os.path.join(
            constants.CONST.__getattribute__('dir_results'), 'robot')
        self.xml_file = os.path.join(self.res_dir, 'output.xml')
        super(RobotFramework, self).__init__(**kwargs)

    def parse_results(self):
        """Parse output.xml and get the details in it."""
        result = robot.api.ExecutionResult(self.xml_file)
        visitor = ResultVisitor()
        result.visit(visitor)
        try:
            self.result = 100 * (
                result.suite.statistics.critical.passed /
                result.suite.statistics.critical.total)
        except ZeroDivisionError:
            self.__logger.error("No test has been run")
        self.start_time = timestamp_to_secs(result.suite.starttime)
        self.stop_time = timestamp_to_secs(result.suite.endtime)
        self.details = {}
        self.details['description'] = result.suite.name
        self.details['tests'] = visitor.get_data()

    def run(self, **kwargs):
        """Run the RobotFramework suites

        Here are the steps:
           * create the output directories if required,
           * get the results in output.xml,
           * delete temporary files.

        Args:
            kwargs: Arbitrary keyword arguments.

        Returns:
            EX_OK if all suites ran well.
            EX_RUN_ERROR otherwise.
        """
        try:
            suites = kwargs["suites"]
            variable = kwargs.get("variable", [])
        except KeyError:
            self.__logger.exception("Mandatory args were not passed")
            return self.EX_RUN_ERROR
        try:
            os.makedirs(self.res_dir)
        except OSError as ex:
            if ex.errno != errno.EEXIST:
                self.__logger.exception("Cannot create %s", self.res_dir)
                return self.EX_RUN_ERROR
        except Exception:  # pylint: disable=broad-except
            self.__logger.exception("Cannot create %s", self.res_dir)
            return self.EX_RUN_ERROR
        stream = StringIO()
        robot.run(*suites, variable=variable, output=self.xml_file,
                  log='NONE', report='NONE', stdout=stream)
        self.__logger.info("\n" + stream.getvalue())
        self.__logger.info("Results were successfully generated")
        try:
            self.parse_results()
            self.__logger.info("Results were successfully parsed")
        except RobotError as ex:
            self.__logger.error("Run suites before publishing: %s", ex.message)
            return self.EX_RUN_ERROR
        except Exception:  # pylint: disable=broad-except
            self.__logger.exception("Cannot parse results")
            return self.EX_RUN_ERROR
        return self.EX_OK