Robot Framework
status.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 from robot.errors import PassExecution
17 from robot.model import TagPatterns
18 from robot.utils import html_escape, test_or_task
19 
20 
21 class Failure:
22 
23  def __init__(self):
24  self.setupsetup = None
25  self.testtest = None
26  self.teardownteardown = None
27  self.setup_skippedsetup_skipped = None
28  self.test_skippedtest_skipped = None
29  self.teardown_skippedteardown_skipped = None
30 
31  def __bool__(self):
32  return bool(
33  self.setupsetup or self.testtest or self.teardownteardown or
34  self.setup_skippedsetup_skipped or self.test_skippedtest_skipped or self.teardown_skippedteardown_skipped
35  )
36 
37 
38 class Exit:
39 
40  def __init__(self, failure_mode=False, error_mode=False, skip_teardown_mode=False):
41  self.failure_modefailure_mode = failure_mode
42  self.error_modeerror_mode = error_mode
43  self.skip_teardown_modeskip_teardown_mode = skip_teardown_mode
44  self.failurefailure = False
45  self.errorerror = False
46  self.fatalfatal = False
47 
48  def failure_occurred(self, fatal=False):
49  if fatal:
50  self.fatalfatal = True
51  if self.failure_modefailure_mode:
52  self.failurefailure = True
53 
54  def error_occurred(self):
55  if self.error_modeerror_mode:
56  self.errorerror = True
57 
58  @property
59  teardown_allowed = property
60 
61  def teardown_allowed(self):
62  return not (self.skip_teardown_modeskip_teardown_mode and self)
63 
64  def __bool__(self):
65  return bool(self.failurefailure or self.errorerror or self.fatalfatal)
66 
67 
69 
70  def __init__(self, parent, exit=None):
71  self.parentparent = parent
72  self.exitexit = exit if exit is not None else parent.exit
73  self.failurefailure = Failure()
74  self.skippedskipped = False
75  self._teardown_allowed_teardown_allowed = False
76  self._rpa_rpa = False
77 
78  @property
79  failed = property
80 
81  def failed(self):
82  return bool(self.parentparent and self.parentparent.failed or self.failurefailure or self.exitexit)
83 
84  @property
85  passed = property
86 
87  def passed(self):
88  return not self.failedfailedfailed
89 
90  def setup_executed(self, error=None):
91  if error and not isinstance(error, PassExecution):
92  msg = str(error)
93  if error.skip:
94  self.failurefailure.setup_skipped = msg
95  self.skippedskipped = True
96  elif self._skip_on_failure_skip_on_failure():
97  self.failurefailure.test = self._skip_on_fail_msg_skip_on_fail_msg(f'Setup failed:\n{msg}')
98  self.skippedskipped = True
99  else:
100  self.failurefailure.setup = msg
101  self.exitexit.failure_occurred(error.exit)
102  self._teardown_allowed_teardown_allowed = True
103 
104  def teardown_executed(self, error=None):
105  if error and not isinstance(error, PassExecution):
106  msg = str(error)
107  if error.skip:
108  self.failurefailure.teardown_skipped = msg
109  self.skippedskipped = True
110  elif self._skip_on_failure_skip_on_failure():
111  self.failurefailure.test = self._skip_on_fail_msg_skip_on_fail_msg(f'Teardown failed:\n{msg}')
112  self.skippedskipped = True
113  else:
114  self.failurefailure.teardown = msg
115  self.exitexit.failure_occurred(error.exit)
116 
117  def failure_occurred(self):
118  self.exitexit.failure_occurred()
119 
120  def error_occurred(self):
121  self.exitexit.error_occurred()
122 
123  @property
124  teardown_allowed = property
125 
126  def teardown_allowed(self):
127  return self.exitexit.teardown_allowed and self._teardown_allowed_teardown_allowed
128 
129  @property
130  status = property
131 
132  def status(self):
133  if self.skippedskipped or (self.parentparent and self.parentparent.skipped):
134  return 'SKIP'
135  if self.failedfailedfailed:
136  return 'FAIL'
137  return 'PASS'
138 
139  def _skip_on_failure(self):
140  return False
141 
142  def _skip_on_fail_msg(self, msg):
143  return msg
144 
145  @property
146  message = property
147 
148  def message(self):
149  if self.failurefailure or self.exitexit:
150  return self._my_message_my_message()
151  if self.parentparent and not self.parentparent.passed:
152  return self._parent_message_parent_message()
153  return ''
154 
155  def _my_message(self):
156  raise NotImplementedError
157 
158  def _parent_message(self):
159  return ParentMessage(self.parentparent).message
160 
161 
163 
164  def __init__(self, parent=None, exit_on_failure=False, exit_on_error=False,
165  skip_teardown_on_exit=False):
166  if parent is None:
167  exit = Exit(exit_on_failure, exit_on_error, skip_teardown_on_exit)
168  else:
169  exit = None
170  super().__init__(parent, exit)
171 
172  def _my_message(self):
173  return SuiteMessage(self).message
174 
175 
177 
178  def __init__(self, parent, test, skip_on_failure=None, rpa=False):
179  super().__init__(parent)
180  self._test_test = test
181  self._skip_on_failure_tags_skip_on_failure_tags = skip_on_failure
182  self._rpa_rpa_rpa = rpa
183 
184  def test_failed(self, message=None, error=None):
185  if error is not None:
186  message = str(error)
187  skip = error.skip
188  fatal = error.exit
189  else:
190  skip = fatal = False
191  if skip:
192  self.test_skippedtest_skipped(message)
193  elif self._skip_on_failure_skip_on_failure_skip_on_failure():
194  self.failurefailure.test = self._skip_on_fail_msg_skip_on_fail_msg_skip_on_fail_msg(message)
195  self.skippedskippedskipped = True
196  else:
197  self.failurefailure.test = message
198  self.exitexit.failure_occurred(fatal)
199 
200  def test_skipped(self, message):
201  self.skippedskippedskipped = True
202  self.failurefailure.test_skipped = message
203 
204  @property
205  skip_on_failure_after_tag_changes = property
206 
208  if not self.skippedskippedskipped and self.failedfailedfailed and self._skip_on_failure_skip_on_failure_skip_on_failure():
209  self.failurefailure.test = self._skip_on_fail_msg_skip_on_fail_msg_skip_on_fail_msg(self.failurefailure.test)
210  self.skippedskippedskipped = True
211  return True
212  return False
213 
214  def _skip_on_failure(self):
215  return (self._test_test.tags.robot('skip-on-failure')
216  or self._skip_on_failure_tags_skip_on_failure_tags
217  and TagPatterns(self._skip_on_failure_tags_skip_on_failure_tags).match(self._test_test.tags))
218 
219  def _skip_on_fail_msg(self, msg):
220  return test_or_task(
221  "{Test} failed but skip-on-failure mode was active and it was marked "
222  "skipped.\n\nOriginal failure:\n%s" % msg, rpa=self._rpa_rpa_rpa
223  )
224 
225  def _my_message(self):
226  return TestMessage(self).message
227 
228 
229 class _Message:
230  setup_message = NotImplemented
231  setup_skipped_message = NotImplemented
232  teardown_skipped_message = NotImplemented
233  teardown_message = NotImplemented
234  also_teardown_message = NotImplemented
235 
236  def __init__(self, status):
237  self.failurefailure = status.failure
238  self.skippedskipped = status.skipped
239 
240  @property
241  message = property
242 
243  def message(self):
244  message = self._get_message_before_teardown_get_message_before_teardown()
245  return self._get_message_after_teardown_get_message_after_teardown(message)
246 
248  if self.failurefailure.setup_skipped:
249  return self._format_setup_or_teardown_message_format_setup_or_teardown_message(
250  self.setup_skipped_messagesetup_skipped_message, self.failurefailure.setup_skipped)
251  if self.failurefailure.setup:
252  return self._format_setup_or_teardown_message_format_setup_or_teardown_message(
253  self.setup_messagesetup_message, self.failurefailure.setup)
254  return self.failurefailure.test_skipped or self.failurefailure.test or ''
255 
256  def _format_setup_or_teardown_message(self, prefix, message):
257  if message.startswith('*HTML*'):
258  prefix = '*HTML* ' + prefix
259  message = message[6:].lstrip()
260  return prefix % message
261 
262  def _get_message_after_teardown(self, message):
263  if not (self.failurefailure.teardown or self.failurefailure.teardown_skipped):
264  return message
265  if not message:
266  if self.failurefailure.teardown:
267  prefix, msg = self.teardown_messageteardown_message, self.failurefailure.teardown
268  else:
269  prefix, msg = self.teardown_skipped_messageteardown_skipped_message, self.failurefailure.teardown_skipped
270  return self._format_setup_or_teardown_message_format_setup_or_teardown_message(prefix, msg)
271  return self._format_message_with_teardown_message_format_message_with_teardown_message(message)
272 
274  teardown = self.failurefailure.teardown or self.failurefailure.teardown_skipped
275  if teardown.startswith('*HTML*'):
276  teardown = teardown[6:].lstrip()
277  if not message.startswith('*HTML*'):
278  message = '*HTML* ' + html_escape(message)
279  elif message.startswith('*HTML*'):
280  teardown = html_escape(teardown)
281  if self.failurefailure.teardown:
282  return self.also_teardown_messagealso_teardown_message % (message, teardown)
283  return self.also_teardown_skip_message % (teardown, message)
284 
285 
287  setup_message = 'Setup failed:\n%s'
288  teardown_message = 'Teardown failed:\n%s'
289  setup_skipped_message = '%s'
290  teardown_skipped_message = '%s'
291  also_teardown_message = '%s\n\nAlso teardown failed:\n%s'
292  also_teardown_skip_message = 'Skipped in teardown:\n%s\n\nEarlier message:\n%s'
293  exit_on_fatal_message = 'Test execution stopped due to a fatal error.'
294  exit_on_failure_message = \
295  'Failure occurred and exit-on-failure mode is in use.'
296  exit_on_error_message = 'Error occurred and exit-on-error mode is in use.'
297 
298  def __init__(self, status):
299  _Message.__init__(self, status)
300  self.exitexit = status.exit
301 
302  @property
303  message = property
304 
305  def message(self):
306  message = super().message
307  if message:
308  return message
309  if self.exitexit.failure:
310  return self.exit_on_failure_messageexit_on_failure_message
311  if self.exitexit.fatal:
312  return self.exit_on_fatal_messageexit_on_fatal_message
313  if self.exitexit.error:
314  return self.exit_on_error_messageexit_on_error_message
315  return ''
316 
317 
319  setup_message = 'Suite setup failed:\n%s'
320  setup_skipped_message = 'Skipped in suite setup:\n%s'
321  teardown_skipped_message = 'Skipped in suite teardown:\n%s'
322  teardown_message = 'Suite teardown failed:\n%s'
323  also_teardown_message = '%s\n\nAlso suite teardown failed:\n%s'
324  also_teardown_skip_message = 'Skipped in suite teardown:\n%s\n\nEarlier message:\n%s'
325 
326 
328  setup_message = 'Parent suite setup failed:\n%s'
329  setup_skipped_message = 'Skipped in parent suite setup:\n%s'
330  teardown_skipped_message = 'Skipped in parent suite teardown:\n%s'
331  teardown_message = 'Parent suite teardown failed:\n%s'
332  also_teardown_message = '%s\n\nAlso parent suite teardown failed:\n%s'
333 
334  def __init__(self, status):
335  while status.parent and status.parent.failed:
336  status = status.parent
337  SuiteMessage.__init__(self, status)
def error_occurred(self)
Definition: status.py:54
def failure_occurred(self, fatal=False)
Definition: status.py:48
def __init__(self, failure_mode=False, error_mode=False, skip_teardown_mode=False)
Definition: status.py:40
def __init__(self, status)
Definition: status.py:334
def __init__(self, parent=None, exit_on_failure=False, exit_on_error=False, skip_teardown_on_exit=False)
Definition: status.py:165
def __init__(self, status)
Definition: status.py:298
def test_skipped(self, message)
Definition: status.py:200
def test_failed(self, message=None, error=None)
Definition: status.py:184
def __init__(self, parent, test, skip_on_failure=None, rpa=False)
Definition: status.py:178
def _skip_on_fail_msg(self, msg)
Definition: status.py:219
def teardown_executed(self, error=None)
Definition: status.py:104
def setup_executed(self, error=None)
Definition: status.py:90
def __init__(self, parent, exit=None)
Definition: status.py:70
def _get_message_before_teardown(self)
Definition: status.py:247
def _get_message_after_teardown(self, message)
Definition: status.py:262
def __init__(self, status)
Definition: status.py:236
def _format_setup_or_teardown_message(self, prefix, message)
Definition: status.py:256
def _format_message_with_teardown_message(self, message)
Definition: status.py:273
def html_escape(text, linkify=True)
Definition: markuputils.py:44
def test_or_task(str text, bool rpa)
Replace 'test' with 'task' in the given text depending on rpa.
Definition: misc.py:105