Revision: d2930be57486
Author: Janne Härkönen <[email protected]>
Date: Fri May 6 04:52:43 2011
Log: Implemented keyword teardown functionality
Update issue 711
Owner: janne.t.harkonen
Cc: pekka.klarck
Still need to add tests for dry run and update user guide.
http://code.google.com/p/robotframework/source/detail?r=d2930be57486
Modified:
/src/robot/parsing/model.py
/src/robot/running/context.py
/src/robot/running/fixture.py
/src/robot/running/runerrors.py
/src/robot/running/userkeyword.py
/utest/parsing/test_model.py
=======================================
--- /src/robot/parsing/model.py Fri Apr 15 14:27:57 2011
+++ /src/robot/parsing/model.py Fri May 6 04:52:43 2011
@@ -464,7 +464,7 @@
self.parent.report_invalid_syntax(message, level)
def __iter__(self):
- for element in [self.doc, self.tags, self.setup,
+ for element in [self.doc, self.tags, self.setup,
self.template, self.timeout] \
+ self.steps + [self.teardown]:
yield element
@@ -479,17 +479,19 @@
self.args = Arguments('[Arguments]', self)
self.return_ = Return('[Return]', self)
self.timeout = Timeout('[Timeout]', self)
+ self.teardown = Fixture('[Teardown]', self)
self.steps = []
_setters = {'documentation': lambda s: s.doc.populate,
'document': lambda s: s.doc.populate,
'arguments': lambda s: s.args.populate,
'return': lambda s: s.return_.populate,
- 'timeout': lambda s: s.timeout.populate}
+ 'timeout': lambda s: s.timeout.populate,
+ 'teardown': lambda s: s.teardown.populate}
def __iter__(self):
for element in [self.args, self.doc, self.timeout] \
- + self.steps + [self.return_]:
+ + self.steps + [self.teardown, self.return_]:
yield element
=======================================
--- /src/robot/running/context.py Sun Feb 6 01:24:10 2011
+++ /src/robot/running/context.py Fri May 6 04:52:43 2011
@@ -21,12 +21,22 @@
self.namespace = namespace
self.output = output
self.dry_run = dry_run
+ self._in_teardown = False
@property
def teardown(self):
+ if self._in_teardown:
+ return True
+ # TODO: tests and suites should also call start/end_teardown()
test_or_suite = self.namespace.test or self.namespace.suite
return test_or_suite.status != 'RUNNING'
+ def start_teardown(self):
+ self._in_teardown = True
+
+ def end_teardown(self):
+ self._in_teardown = False
+
def get_current_vars(self):
return self.namespace.variables
=======================================
--- /src/robot/running/fixture.py Sun Feb 6 01:24:10 2011
+++ /src/robot/running/fixture.py Fri May 6 04:52:43 2011
@@ -83,4 +83,11 @@
class TestTeardownListener(_TestListener):
def _notify_run_errors(self, error):
- self._test.run_errors.teardown_err(unicode(error))
+ self._test.run_errors.teardown_err(error)
+
+
+class KeywordTeardownListener(object):
+ def __init__(self, run_errors):
+ self._run_errors = run_errors
+ def notify(self, error):
+ self._run_errors.teardown_err(error)
=======================================
--- /src/robot/running/runerrors.py Sun Feb 6 01:24:10 2011
+++ /src/robot/running/runerrors.py Fri May 6 04:52:43 2011
@@ -156,9 +156,31 @@
return self._kw_err
def get_teardown_message(self, message):
+ # TODO: This API is really in need of cleanup
if message == '':
return 'Teardown failed:\n%s' % self._teardown_err
return '%s\n\nAlso teardown failed:\n%s' % (message,
self._teardown_err)
def parent_or_init_error(self):
return self._parent_err or self._init_err
+
+
+class KeywordRunErrors(object):
+
+ def __init__(self):
+ self._kw_err = ''
+ self._teardown_err = ''
+
+ def get_message(self):
+ if not self._teardown_err:
+ return self._kw_err
+ if not self._kw_err:
+ return 'Keyword teardown failed:\n%s' % self._teardown_err
+ return '%s\n\nAlso keyword teardown failed:\n%s' % (self._kw_err,
+
self._teardown_err)
+
+ def kw_err(self, error):
+ self._kw_err = unicode(error)
+
+ def teardown_err(self, err):
+ self._teardown_err = unicode(err)
=======================================
--- /src/robot/running/userkeyword.py Sun Feb 6 01:24:10 2011
+++ /src/robot/running/userkeyword.py Fri May 6 04:52:43 2011
@@ -16,13 +16,15 @@
import re
from robot.common import BaseLibrary, UserErrorHandler
-from robot.errors import DataError
+from robot.errors import DataError, ExecutionFailed
from robot.variables import is_list_var, VariableSplitter
from robot import utils
from keywords import Keywords
+from fixture import Teardown, KeywordTeardownListener
from timeouts import KeywordTimeout
from arguments import UserKeywordArguments
+from runerrors import KeywordRunErrors
class UserLibrary(BaseLibrary):
@@ -98,6 +100,7 @@
self.name = keyword.name
self.keywords = Keywords(keyword.steps)
self.return_value = keyword.return_.value
+ self.teardown = keyword.teardown
self._libname = libname
self.doc = self._doc = keyword.doc.value
self._timeout = keyword.timeout
@@ -146,7 +149,22 @@
args_spec.set_variables(resolved_arguments, variables,
context.output)
self._verify_keyword_is_valid()
self.timeout.start()
- self.keywords.run(context)
+ run_errors = KeywordRunErrors()
+ try:
+ self.keywords.run(context)
+ except ExecutionFailed, err:
+ run_errors.kw_err(err)
+ self._run_teardown(context, run_errors)
+ msg = run_errors.get_message()
+ if msg:
+ raise ExecutionFailed(msg)
+
+ def _run_teardown(self, context, run_errors):
+ teardown = Teardown(self.teardown.name, self.teardown.args)
+ teardown.replace_variables(context.get_current_vars(), [])
+ context.start_teardown()
+ teardown.run(context, KeywordTeardownListener(run_errors))
+ context.end_teardown()
def _verify_keyword_is_valid(self):
if self._errors:
=======================================
--- /utest/parsing/test_model.py Thu Jan 27 07:26:13 2011
+++ /utest/parsing/test_model.py Fri May 6 04:52:43 2011
@@ -109,7 +109,7 @@
self._verify_import(self.table.add_variables('./v2.py',
['a1', 'a2']),
'./v2.py', ['a1', 'a2'])
self._verify_import(self.table.add_library('N2',
['1', '2', '3', '4']),
- 'N2', ['1', '2', '3', '4'])
+ 'N2', ['1', '2', '3', '4'])
assert_equal(len(self.table.imports), 5)
assert_true(all(isinstance(im, _Import) for im in
self.table.imports))
@@ -160,7 +160,7 @@
self.table.add('not var', 'the value')
assert_equal(self.table.variables[0].name, 'not var')
assert_equal(self.table.variables[0].value, ['the value'])
-
+
class TestTestCaseTable(unittest.TestCase):
@@ -221,6 +221,7 @@
assert_true(isinstance(self.kw.args, Arguments))
assert_true(isinstance(self.kw.return_, Return))
assert_true(isinstance(self.kw.timeout, Timeout))
+ assert_true(isinstance(self.kw.teardown, Fixture))
def test_set_settings(self):
self.kw.doc.populate('My coooool doc')
@@ -307,7 +308,7 @@
def test_in_range(self):
self._test(['${i}', 'IN RANGE', '100'], ['${i}'], ['100'],
range=True)
- self._test(['what', 'ever', 'in range', 'IN', 'whatever'],
+ self._test(['what', 'ever', 'in range', 'IN', 'whatever'],
['what', 'ever'], ['IN', 'whatever'], range=True)
def test_representation(self):