3 # Copyright (c) 2016 Orange and others.
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
10 """Define the parent class of all Functest TestCases."""
17 import functest.utils.functest_utils as ft_utils
18 import functest.utils.openstack_clean as os_clean
19 import functest.utils.openstack_snapshot as os_snapshot
21 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
24 class TestCase(object):
25 """Base model for single test case."""
28 """everything is OK"""
30 EX_RUN_ERROR = os.EX_SOFTWARE
33 EX_PUSH_TO_DB_ERROR = os.EX_SOFTWARE - 1
34 """push_to_db() failed"""
36 EX_TESTCASE_FAILED = os.EX_SOFTWARE - 2
37 """results are false"""
39 __logger = logging.getLogger(__name__)
41 def __init__(self, **kwargs):
43 self.project_name = kwargs.get('project_name', 'functest')
44 self.case_name = kwargs.get('case_name', '')
45 self.criteria = kwargs.get('criteria', 100)
52 assert self.project_name
54 result = 'PASS' if(self.is_successful(
55 ) == TestCase.EX_OK) else 'FAIL'
56 msg = prettytable.PrettyTable(
57 header_style='upper', padding_width=5,
58 field_names=['test case', 'project', 'duration',
60 msg.add_row([self.case_name, self.project_name,
61 self.get_duration(), result])
62 return msg.get_string()
63 except AssertionError:
64 self.__logger.error("We cannot print invalid objects")
65 return super(TestCase, self).__str__()
67 def get_duration(self):
68 """Return the duration of the test case.
71 duration if start_time and stop_time are set
75 assert self.start_time
77 if self.stop_time < self.start_time:
79 return "{0[0]:02.0f}:{0[1]:02.0f}".format(divmod(
80 self.stop_time - self.start_time, 60))
81 except Exception: # pylint: disable=broad-except
82 self.__logger.error("Please run test before getting the duration")
85 def is_successful(self):
86 """Interpret the result of the test case.
88 It allows getting the result of TestCase. It completes run()
89 which only returns the execution status.
91 It can be overriden if checking result is not suitable.
94 TestCase.EX_OK if result is 'PASS'.
95 TestCase.EX_TESTCASE_FAILED otherwise.
99 assert self.result is not None
100 if (not isinstance(self.result, str) and
101 not isinstance(self.criteria, str)):
102 if self.result >= self.criteria:
103 return TestCase.EX_OK
105 # Backward compatibility
106 # It must be removed as soon as TestCase subclasses
107 # stop setting result = 'PASS' or 'FAIL'.
108 # In this case criteria is unread.
109 self.__logger.warning(
110 "Please update result which must be an int!")
111 if self.result == 'PASS':
112 return TestCase.EX_OK
113 except AssertionError:
114 self.__logger.error("Please run test before checking the results")
115 return TestCase.EX_TESTCASE_FAILED
117 def run(self, **kwargs):
118 """Run the test case.
120 It allows running TestCase and getting its execution
123 The subclasses must override the default implementation which
126 The new implementation must set the following attributes to
127 push the results to DB:
134 kwargs: Arbitrary keyword arguments.
137 TestCase.EX_RUN_ERROR.
139 # pylint: disable=unused-argument
140 self.__logger.error("Run must be implemented")
141 return TestCase.EX_RUN_ERROR
143 def push_to_db(self):
144 """Push the results of the test case to the DB.
146 It allows publishing the results and to check the status.
148 It could be overriden if the common implementation is not
149 suitable. The following attributes must be set before pushing
159 TestCase.EX_OK if results were pushed to DB.
160 TestCase.EX_PUSH_TO_DB_ERROR otherwise.
163 assert self.project_name
164 assert self.case_name
165 assert self.start_time
166 assert self.stop_time
167 pub_result = 'PASS' if self.is_successful(
168 ) == TestCase.EX_OK else 'FAIL'
169 if ft_utils.push_results_to_db(
170 self.project_name, self.case_name, self.start_time,
171 self.stop_time, pub_result, self.details):
173 "The results were successfully pushed to DB")
174 return TestCase.EX_OK
176 self.__logger.error("The results cannot be pushed to DB")
177 return TestCase.EX_PUSH_TO_DB_ERROR
178 except Exception: # pylint: disable=broad-except
179 self.__logger.exception("The results cannot be pushed to DB")
180 return TestCase.EX_PUSH_TO_DB_ERROR
182 def create_snapshot(self): # pylint: disable=no-self-use
183 """Save the testing environment before running test.
185 It can be overriden if resources must be listed running the
191 return TestCase.EX_OK
194 """Clean the resources.
196 It can be overriden if resources must be deleted after
197 running the test case.
201 class OSGCTestCase(TestCase):
202 """Model for single test case which requires an OpenStack Garbage
205 __logger = logging.getLogger(__name__)
207 def create_snapshot(self):
208 """Create a snapshot listing the OpenStack resources.
211 TestCase.EX_OK if os_snapshot.main() returns 0.
212 TestCase.EX_RUN_ERROR otherwise.
215 assert os_snapshot.main() == 0
216 self.__logger.info("OpenStack resources snapshot created")
217 return TestCase.EX_OK
218 except Exception: # pylint: disable=broad-except
219 self.__logger.exception("Cannot create the snapshot")
220 return TestCase.EX_RUN_ERROR
223 """Clean the OpenStack resources."""
225 assert os_clean.main() == 0
226 self.__logger.info("OpenStack resources cleaned")
227 except Exception: # pylint: disable=broad-except
228 self.__logger.exception("Cannot clean the OpenStack resources")