Robot Framework Integrated Development Environment (RIDE)
runner.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 robotide.lib.robot.errors import ExecutionFailed, ExecutionStatus, DataError, PassExecution
17 from robotide.lib.robot.model import SuiteVisitor
18 from robotide.lib.robot.result import TestSuite, Result
19 from robotide.lib.robot.utils import get_timestamp, is_list_like, NormalizedDict, unic
20 from robotide.lib.robot.variables import VariableScopes
21 
22 from .context import EXECUTION_CONTEXTS
23 from .steprunner import StepRunner
24 from .namespace import Namespace
25 from .status import SuiteStatus, TestStatus
26 from .timeouts import TestTimeout
27 
28 
29 # Some 'extract method' love needed here. Perhaps even 'extract class'.
30 
32 
33  def __init__(self, output, settings):
34  self.resultresult = None
35  self._output_output = output
36  self._settings_settings = settings
37  self._variables_variables = VariableScopes(settings)
38  self._suite_suite = None
39  self._suite_status_suite_status = None
40  self._executed_tests_executed_tests = None
41 
42  @property
43  _context = property
44 
45  def _context(self):
46  return EXECUTION_CONTEXTS.current
47 
48  def start_suite(self, suite):
49  self._output_output.library_listeners.new_suite_scope()
50  result = TestSuite(source=suite.source,
51  name=suite.name,
52  doc=suite.doc,
53  metadata=suite.metadata,
54  starttime=get_timestamp(),
55  rpa=self._settings_settings.rpa)
56  if not self.resultresult:
57  result.set_criticality(self._settings_settings.critical_tags,
58  self._settings_settings.non_critical_tags)
59  self.resultresult = Result(root_suite=result, rpa=self._settings_settings.rpa)
60  self.resultresult.configure(status_rc=self._settings_settings.status_rc,
61  stat_config=self._settings_settings.statistics_config)
62  else:
63  self._suite_suite.suites.append(result)
64  self._suite_suite = result
65  self._suite_status_suite_status = SuiteStatus(self._suite_status_suite_status,
66  self._settings_settings.exit_on_failure,
67  self._settings_settings.exit_on_error,
68  self._settings_settings.skip_teardown_on_exit)
69  ns = Namespace(self._variables_variables, result, suite.resource)
70  ns.start_suite()
71  ns.variables.set_from_variable_table(suite.resource.variables)
72  EXECUTION_CONTEXTS.start_suite(result, ns, self._output_output,
73  self._settings_settings.dry_run)
74  self._context_context_context.set_suite_variables(result)
75  if not self._suite_status_suite_status.failures:
76  ns.handle_imports()
77  ns.variables.resolve_delayed()
78  result.doc = self._resolve_setting_resolve_setting(result.doc)
79  result.metadata = [(self._resolve_setting_resolve_setting(n), self._resolve_setting_resolve_setting(v))
80  for n, v in result.metadata.items()]
81  self._context_context_context.set_suite_variables(result)
82  self._output_output.start_suite(ModelCombiner(suite, result,
83  tests=suite.tests,
84  suites=suite.suites,
85  test_count=suite.test_count))
86  self._output_output.register_error_listener(self._suite_status_suite_status.error_occurred)
87  self._run_setup_run_setup(suite.keywords.setup, self._suite_status_suite_status)
88  self._executed_tests_executed_tests = NormalizedDict(ignore='_')
89 
90  def _resolve_setting(self, value):
91  if is_list_like(value):
92  return self._variables_variables.replace_list(value, ignore_errors=True)
93  return self._variables_variables.replace_string(value, ignore_errors=True)
94 
95  def end_suite(self, suite):
96  self._suite_suite.message = self._suite_status_suite_status.message
97  self._context_context_context.report_suite_status(self._suite_suite.status,
98  self._suite_suite.full_message)
99  with self._context_context_context.suite_teardown():
100  failure = self._run_teardown_run_teardown(suite.keywords.teardown, self._suite_status_suite_status)
101  if failure:
102  self._suite_suite.suite_teardown_failed(unic(failure))
103  if self._suite_suite.statistics.critical.failed:
104  self._suite_status_suite_status.critical_failure_occurred()
105  self._suite_suite.endtime = get_timestamp()
106  self._suite_suite.message = self._suite_status_suite_status.message
107  self._context_context_context.end_suite(ModelCombiner(suite, self._suite_suite))
108  self._suite_suite = self._suite_suite.parent
109  self._suite_status_suite_status = self._suite_status_suite_status.parent
110  self._output_output.library_listeners.discard_suite_scope()
111 
112  def visit_test(self, test):
113  if test.name in self._executed_tests_executed_tests:
114  self._output_output.warn("Multiple test cases with name '%s' executed in "
115  "test suite '%s'." % (test.name, self._suite_suite.longname))
116  self._executed_tests_executed_tests[test.name] = True
117  result = self._suite_suite.tests.create(name=test.name,
118  doc=self._resolve_setting_resolve_setting(test.doc),
119  tags=self._resolve_setting_resolve_setting(test.tags),
120  starttime=get_timestamp(),
121  timeout=self._get_timeout_get_timeout(test))
122  self._context_context_context.start_test(result)
123  self._output_output.start_test(ModelCombiner(test, result))
124  status = TestStatus(self._suite_status_suite_status, result.critical)
125  if status.exit:
126  self._add_exit_combine_add_exit_combine()
127  result.tags.add('robot:exit')
128  if not status.failures and not test.name:
129  status.test_failed('Test case name cannot be empty.')
130  if not status.failures and not test.keywords.normal:
131  status.test_failed('Test case contains no keywords.')
132  self._run_setup_run_setup(test.keywords.setup, status, result)
133  try:
134  if not status.failures:
135  StepRunner(self._context_context_context,
136  test.template).run_steps(test.keywords.normal)
137  else:
138  status.test_failed(status.message)
139  except PassExecution as exception:
140  err = exception.earlier_failures
141  if err:
142  status.test_failed(err)
143  else:
144  result.message = exception.message
145  except ExecutionStatus as err:
146  status.test_failed(err)
147  result.status = status.status
148  result.message = status.message or result.message
149  if status.teardown_allowed:
150  with self._context_context_context.test_teardown(result):
151  failure = self._run_teardown_run_teardown(test.keywords.teardown, status,
152  result)
153  if failure and result.critical:
154  status.critical_failure_occurred()
155  if not status.failures and result.timeout and result.timeout.timed_out():
156  status.test_failed(result.timeout.get_message())
157  result.message = status.message
158  result.status = status.status
159  result.endtime = get_timestamp()
160  self._output_output.end_test(ModelCombiner(test, result))
161  self._context_context_context.end_test(result)
162 
163  def _add_exit_combine(self):
164  exit_combine = ('NOT robot:exit', '')
165  if exit_combine not in self._settings_settings['TagStatCombine']:
166  self._settings_settings['TagStatCombine'].append(exit_combine)
167 
168  def _get_timeout(self, test):
169  if not test.timeout:
170  return None
171  return TestTimeout(test.timeout.value, test.timeout.message,
172  self._variables_variables, rpa=test.parent.rpa)
173 
174  def _run_setup(self, setup, status, result=None):
175  if not status.failures:
176  exception = self._run_setup_or_teardown_run_setup_or_teardown(setup)
177  status.setup_executed(exception)
178  if result and isinstance(exception, PassExecution):
179  result.message = exception.message
180 
181  def _run_teardown(self, teardown, status, result=None):
182  if status.teardown_allowed:
183  exception = self._run_setup_or_teardown_run_setup_or_teardown(teardown)
184  status.teardown_executed(exception)
185  failed = not isinstance(exception, PassExecution)
186  if result and exception:
187  result.message = status.message if failed else exception.message
188  return exception if failed else None
189 
190  def _run_setup_or_teardown(self, data):
191  if not data:
192  return None
193  try:
194  name = self._variables_variables.replace_string(data.name)
195  except DataError as err:
196  if self._settings_settings.dry_run:
197  return None
198  return err
199  if name.upper() in ('', 'NONE'):
200  return None
201  try:
202  StepRunner(self._context_context_context).run_step(data, name=name)
203  except ExecutionStatus as err:
204  return err
205 
206 
208 
209  def __init__(self, data, result, **priority):
210  self.datadata = data
211  self.resultresult = result
212  self.prioritypriority = priority
213 
214  def __getattr__(self, name):
215  if name in self.prioritypriority:
216  return self.prioritypriority[name]
217  if hasattr(self.resultresult, name):
218  return getattr(self.resultresult, name)
219  if hasattr(self.datadata, name):
220  return getattr(self.datadata, name)
221  raise AttributeError(name)
Interface to ease traversing through a test suite structure.
Definition: visitor.py:75
def start_test(self, test)
Called when test starts.
Definition: visitor.py:115
def end_test(self, test)
Called when test ends.
Definition: visitor.py:119
Represents results of a single test suite.
Definition: model.py:181
def __init__(self, data, result, **priority)
Definition: runner.py:209
def _run_setup(self, setup, status, result=None)
Definition: runner.py:174
def end_suite(self, suite)
Called when suite ends.
Definition: runner.py:95
def visit_test(self, test)
Implements traversing through the test and its keywords.
Definition: runner.py:112
def _run_teardown(self, teardown, status, result=None)
Definition: runner.py:181
def start_suite(self, suite)
Called when suite starts.
Definition: runner.py:48
def __init__(self, output, settings)
Definition: runner.py:33
def warn(msg, html=False)
Writes the message to the log file using the WARN level.
Definition: logger.py:122
def get_timestamp(daysep='', daytimesep=' ', timesep=':', millissep='.')
Definition: robottime.py:296