Remove OSGCTestCase
[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 import prettytable
18
19
20 __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
21
22
23 class TestCase(object):
24     """Base model for single test case."""
25
26     EX_OK = os.EX_OK
27     """everything is OK"""
28
29     EX_RUN_ERROR = os.EX_SOFTWARE
30     """run() failed"""
31
32     EX_PUSH_TO_DB_ERROR = os.EX_SOFTWARE - 1
33     """push_to_db() failed"""
34
35     EX_TESTCASE_FAILED = os.EX_SOFTWARE - 2
36     """results are false"""
37
38     __logger = logging.getLogger(__name__)
39
40     def __init__(self, **kwargs):
41         self.details = {}
42         self.project_name = kwargs.get('project_name', 'functest')
43         self.case_name = kwargs.get('case_name', '')
44         self.criteria = kwargs.get('criteria', 100)
45         self.result = 0
46         self.start_time = 0
47         self.stop_time = 0
48
49     def __str__(self):
50         try:
51             assert self.project_name
52             assert self.case_name
53             result = 'PASS' if(self.is_successful(
54                 ) == TestCase.EX_OK) else 'FAIL'
55             msg = prettytable.PrettyTable(
56                 header_style='upper', padding_width=5,
57                 field_names=['test case', 'project', 'duration',
58                              'result'])
59             msg.add_row([self.case_name, self.project_name,
60                          self.get_duration(), result])
61             return msg.get_string()
62         except AssertionError:
63             self.__logger.error("We cannot print invalid objects")
64             return super(TestCase, self).__str__()
65
66     def get_duration(self):
67         """Return the duration of the test case.
68
69         Returns:
70             duration if start_time and stop_time are set
71             "XX:XX" otherwise.
72         """
73         try:
74             assert self.start_time
75             assert self.stop_time
76             if self.stop_time < self.start_time:
77                 return "XX:XX"
78             return "{0[0]:02.0f}:{0[1]:02.0f}".format(divmod(
79                 self.stop_time - self.start_time, 60))
80         except Exception:  # pylint: disable=broad-except
81             self.__logger.error("Please run test before getting the duration")
82             return "XX:XX"
83
84     def is_successful(self):
85         """Interpret the result of the test case.
86
87         It allows getting the result of TestCase. It completes run()
88         which only returns the execution status.
89
90         It can be overriden if checking result is not suitable.
91
92         Returns:
93             TestCase.EX_OK if result is 'PASS'.
94             TestCase.EX_TESTCASE_FAILED otherwise.
95         """
96         try:
97             assert self.criteria
98             assert self.result is not None
99             if (not isinstance(self.result, str) and
100                     not isinstance(self.criteria, str)):
101                 if self.result >= self.criteria:
102                     return TestCase.EX_OK
103             else:
104                 # Backward compatibility
105                 # It must be removed as soon as TestCase subclasses
106                 # stop setting result = 'PASS' or 'FAIL'.
107                 # In this case criteria is unread.
108                 self.__logger.warning(
109                     "Please update result which must be an int!")
110                 if self.result == 'PASS':
111                     return TestCase.EX_OK
112         except AssertionError:
113             self.__logger.error("Please run test before checking the results")
114         return TestCase.EX_TESTCASE_FAILED
115
116     def run(self, **kwargs):
117         """Run the test case.
118
119         It allows running TestCase and getting its execution
120         status.
121
122         The subclasses must override the default implementation which
123         is false on purpose.
124
125         The new implementation must set the following attributes to
126         push the results to DB:
127
128             * result,
129             * start_time,
130             * stop_time.
131
132         Args:
133             kwargs: Arbitrary keyword arguments.
134
135         Returns:
136             TestCase.EX_RUN_ERROR.
137         """
138         # pylint: disable=unused-argument
139         self.__logger.error("Run must be implemented")
140         return TestCase.EX_RUN_ERROR
141
142     def push_to_db(self):
143         """Push the results of the test case to the DB.
144
145         It allows publishing the results and to check the status.
146
147         It could be overriden if the common implementation is not
148         suitable. The following attributes must be set before pushing
149         the results to DB:
150
151             * project_name,
152             * case_name,
153             * result,
154             * start_time,
155             * stop_time.
156
157         Returns:
158             TestCase.EX_OK if results were pushed to DB.
159             TestCase.EX_PUSH_TO_DB_ERROR otherwise.
160         """
161         try:
162             assert self.project_name
163             assert self.case_name
164             assert self.start_time
165             assert self.stop_time
166             pub_result = 'PASS' if self.is_successful(
167                 ) == TestCase.EX_OK else 'FAIL'
168             if ft_utils.push_results_to_db(
169                     self.project_name, self.case_name, self.start_time,
170                     self.stop_time, pub_result, self.details):
171                 self.__logger.info(
172                     "The results were successfully pushed to DB")
173                 return TestCase.EX_OK
174             else:
175                 self.__logger.error("The results cannot be pushed to DB")
176                 return TestCase.EX_PUSH_TO_DB_ERROR
177         except Exception:  # pylint: disable=broad-except
178             self.__logger.exception("The results cannot be pushed to DB")
179             return TestCase.EX_PUSH_TO_DB_ERROR
180
181     def create_snapshot(self):  # pylint: disable=no-self-use
182         """Save the testing environment before running test.
183
184         It can be overriden if resources must be listed running the
185         test case.
186
187         Returns:
188             TestCase.EX_OK
189         """
190         return TestCase.EX_OK
191
192     def clean(self):
193         """Clean the resources.
194
195         It can be overriden if resources must be deleted after
196         running the test case.
197         """