Rename TestCase check_result() to is_successful()
[functest.git] / functest / core / testcase.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2016 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 the parent class of all Functest TestCases."""
11
12 import logging
13 import os
14
15 import functest.utils.functest_utils as ft_utils
16
17 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
18
19
20 class TestCase(object):
21     """Base model for single test case."""
22
23     EX_OK = os.EX_OK
24     """everything is OK"""
25
26     EX_RUN_ERROR = os.EX_SOFTWARE
27     """run() failed"""
28
29     EX_PUSH_TO_DB_ERROR = os.EX_SOFTWARE - 1
30     """push_to_db() failed"""
31
32     EX_TESTCASE_FAILED = os.EX_SOFTWARE - 2
33     """results are false"""
34
35     __logger = logging.getLogger(__name__)
36
37     def __init__(self, **kwargs):
38         self.details = {}
39         self.project_name = kwargs.get('project_name', 'functest')
40         self.case_name = kwargs.get('case_name', '')
41         self.criteria = kwargs.get('criteria', 100)
42         self.result = ""
43         self.start_time = ""
44         self.stop_time = ""
45
46     def get_duration(self):
47         """Return the duration of the test case.
48
49         Returns:
50             duration if start_time and stop_time are set
51             "XX:XX" otherwise.
52         """
53         try:
54             assert self.start_time
55             assert self.stop_time
56             if self.stop_time < self.start_time:
57                 return "XX:XX"
58             return "{0[0]:02.0f}:{0[1]:02.0f}".format(divmod(
59                 self.stop_time - self.start_time, 60))
60         except Exception:
61             self.__logger.error("Please run test before getting the duration")
62             return "XX:XX"
63
64     def is_successful(self):
65         """Interpret the result of the test case.
66
67         It allows getting the result of TestCase. It completes run()
68         which only returns the execution status.
69
70         It can be overriden if checking result is not suitable.
71
72         Returns:
73             TestCase.EX_OK if result is 'PASS'.
74             TestCase.EX_TESTCASE_FAILED otherwise.
75         """
76         try:
77             assert self.criteria
78             if isinstance(self.result, int) and isinstance(self.criteria, int):
79                 if self.result >= self.criteria:
80                     return TestCase.EX_OK
81             else:
82                 # Backward compatibility
83                 # It must be removed as soon as TestCase subclasses
84                 # stop setting result = 'PASS' or 'FAIL'.
85                 # In this case criteria is unread.
86                 self.__logger.warning(
87                     "Please update result which must be an int!")
88                 if self.result == 'PASS':
89                     return TestCase.EX_OK
90         except AssertionError:
91             self.__logger.error("Please run test before checking the results")
92         return TestCase.EX_TESTCASE_FAILED
93
94     def run(self, **kwargs):
95         """Run the test case.
96
97         It allows running TestCase and getting its execution
98         status.
99
100         The subclasses must override the default implementation which
101         is false on purpose.
102
103         The new implementation must set the following attributes to
104         push the results to DB:
105
106             * result,
107             * start_time,
108             * stop_time.
109
110         Args:
111             kwargs: Arbitrary keyword arguments.
112
113         Returns:
114             TestCase.EX_RUN_ERROR.
115         """
116         # pylint: disable=unused-argument
117         self.__logger.error("Run must be implemented")
118         return TestCase.EX_RUN_ERROR
119
120     def push_to_db(self):
121         """Push the results of the test case to the DB.
122
123         It allows publishing the results and to check the status.
124
125         It could be overriden if the common implementation is not
126         suitable. The following attributes must be set before pushing
127         the results to DB:
128
129             * project_name,
130             * case_name,
131             * result,
132             * start_time,
133             * stop_time.
134
135         Returns:
136             TestCase.EX_OK if results were pushed to DB.
137             TestCase.EX_PUSH_TO_DB_ERROR otherwise.
138         """
139         try:
140             assert self.project_name
141             assert self.case_name
142             assert self.start_time
143             assert self.stop_time
144             pub_result = 'PASS' if self.is_successful(
145                 ) == TestCase.EX_OK else 'FAIL'
146             if ft_utils.push_results_to_db(
147                     self.project_name, self.case_name, self.start_time,
148                     self.stop_time, pub_result, self.details):
149                 self.__logger.info(
150                     "The results were successfully pushed to DB")
151                 return TestCase.EX_OK
152             else:
153                 self.__logger.error("The results cannot be pushed to DB")
154                 return TestCase.EX_PUSH_TO_DB_ERROR
155         except Exception:  # pylint: disable=broad-except
156             self.__logger.exception("The results cannot be pushed to DB")
157             return TestCase.EX_PUSH_TO_DB_ERROR