4 new revisions:
Revision: d33e9e758a09
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:02:20 2013
Log: atest: more flexible test data for setups/teardowns
http://code.google.com/p/robotframework/source/detail?r=d33e9e758a09
Revision: 45e13e6540d9
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:03:27 2013
Log: moved logic to handle suite teardown failures from result
building to ...
http://code.google.com/p/robotframework/source/detail?r=45e13e6540d9
Revision: 1e9472fb5a28
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:50:08 2013
Log: new run: handle suite setup/teardown failures correctly
http://code.google.com/p/robotframework/source/detail?r=1e9472fb5a28
Revision: 10f3837ff4a8
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:50:12 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=10f3837ff4a8
==============================================================================
Revision: d33e9e758a09
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:02:20 2013
Log: atest: more flexible test data for setups/teardowns
http://code.google.com/p/robotframework/source/detail?r=d33e9e758a09
Modified:
/atest/testdata/misc/setups_and_teardowns.txt
/utest/new_running/test_builder.py
=======================================
--- /atest/testdata/misc/setups_and_teardowns.txt Thu May 23 05:19:59 2013
+++ /atest/testdata/misc/setups_and_teardowns.txt Fri May 24 06:02:20 2013
@@ -1,11 +1,15 @@
***Settings***
Documentation This suite was initially created for testing keyword types
with
... listeners but can be used for other purposes too.
-Suite Setup Suite Setup
-Suite Teardown Suite Teardown
+Suite Setup ${SUITE SETUP}
+Suite Teardown ${SUITE TEARDOWN}
Test Setup Test Setup
Test Teardown Test Teardown
+*** Variables ***
+${SUITE SETUP} Suite Setup
+${SUITE TEARDOWN} Suite Teardown
+
***Test Cases***
Test with setup and teardown
=======================================
--- /utest/new_running/test_builder.py Wed May 22 15:27:57 2013
+++ /utest/new_running/test_builder.py Fri May 24 06:02:20 2013
@@ -81,8 +81,8 @@
def test_suite_setup_and_teardown(self):
suite = self._build('setups_and_teardowns.txt')
- assert_equals(suite.keywords.setup.name, 'Suite Setup')
- assert_equals(suite.keywords.teardown.name, 'Suite Teardown')
+ assert_equals(suite.keywords.setup.name, '${SUITE SETUP}')
+ assert_equals(suite.keywords.teardown.name, '${SUITE TEARDOWN}')
def test_test_setup_and_teardown(self):
test = self._build('setups_and_teardowns.txt').tests[0]
==============================================================================
Revision: 45e13e6540d9
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:03:27 2013
Log: moved logic to handle suite teardown failures from result
building to result object itself. easies reusing it elsewhere.
http://code.google.com/p/robotframework/source/detail?r=45e13e6540d9
Modified:
/src/robot/result/executionresult.py
/src/robot/result/resultbuilder.py
/src/robot/result/suiteteardownfailed.py
/src/robot/result/testsuite.py
/src/robot/result/xmlelementhandlers.py
=======================================
--- /src/robot/result/executionresult.py Wed May 22 04:57:27 2013
+++ /src/robot/result/executionresult.py Fri May 24 06:03:27 2013
@@ -32,7 +32,7 @@
self.source = source
self.suite = root_suite or TestSuite()
self.errors = errors or ExecutionErrors()
- self.generator = None
+ self.generated_by_robot = True
self._status_rc = True
self._stat_config = {}
@@ -62,6 +62,10 @@
from robot.reporting.outputwriter import OutputWriter
self.visit(OutputWriter(path or self.source))
+ def handle_suite_teardown_failures(self):
+ if self.generated_by_robot:
+ self.suite.handle_suite_teardown_failures()
+
class CombinedResult(Result):
=======================================
--- /src/robot/result/resultbuilder.py Sun Oct 21 01:34:33 2012
+++ /src/robot/result/resultbuilder.py Fri May 24 06:03:27 2013
@@ -17,7 +17,6 @@
from robot.errors import DataError
from robot.utils import ET, ETSource, get_error_message
-from .suiteteardownfailed import SuiteTeardownFailureHandler
from .xmlelementhandlers import XmlElementHandler
from .executionresult import Result, CombinedResult
@@ -65,7 +64,7 @@
handler = XmlElementHandler(result)
with self._source as source:
self._parse(source, handler.start, handler.end)
-
SuiteTeardownFailureHandler(result.generator).visit_suite(result.suite)
+ result.handle_suite_teardown_failures()
return result
def _parse(self, source, start, end):
=======================================
--- /src/robot/result/suiteteardownfailed.py Fri Feb 1 00:54:21 2013
+++ /src/robot/result/suiteteardownfailed.py Fri May 24 06:03:27 2013
@@ -17,18 +17,11 @@
class SuiteTeardownFailureHandler(SuiteVisitor):
- def __init__(self, suite_generator):
- self._should_handle = suite_generator == 'ROBOT'
-
- def start_suite(self, suite):
- if not self._should_handle:
- return False
-
def end_suite(self, suite):
teardown = suite.keywords.teardown
# Both 'PASS' and 'NOT_RUN' (used in dry-run) statuses are OK.
if teardown and teardown.status == 'FAIL':
- suite.visit(SuiteTeardownFailed(teardown.message))
+ suite.suite_teardown_failed(teardown.message)
def visit_test(self, test):
pass
=======================================
--- /src/robot/result/testsuite.py Wed May 22 04:57:27 2013
+++ /src/robot/result/testsuite.py Fri May 24 06:03:27 2013
@@ -21,6 +21,8 @@
from .messagefilter import MessageFilter
from .keywordremover import KeywordRemover
from .keyword import Keyword
+from .suiteteardownfailed import (SuiteTeardownFailureHandler,
+ SuiteTeardownFailed)
from .testcase import TestCase
@@ -81,6 +83,12 @@
def configure(self, **options):
self.visit(SuiteConfigurer(**options))
+ def handle_suite_teardown_failures(self):
+ self.visit(SuiteTeardownFailureHandler())
+
+ def suite_teardown_failed(self, message):
+ self.visit(SuiteTeardownFailed(message))
+
# TODO: Remove compatibility code below when new run is integrated
def get_full_message(self):
return self.full_message
=======================================
--- /src/robot/result/xmlelementhandlers.py Thu May 23 05:52:43 2013
+++ /src/robot/result/xmlelementhandlers.py Fri May 24 06:03:27 2013
@@ -65,7 +65,8 @@
tag = 'robot'
def start(self, elem, result):
- result.generator =
elem.get('generator', 'unknown').split()[0].upper()
+ generator = elem.get('generator', 'unknown').split()[0].upper()
+ result.generated_by_robot = generator == 'ROBOT'
return result
def _children(self):
==============================================================================
Revision: 1e9472fb5a28
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:50:08 2013
Log: new run: handle suite setup/teardown failures correctly
http://code.google.com/p/robotframework/source/detail?r=1e9472fb5a28
Modified:
/src/robot/new_running/failures.py
/src/robot/new_running/runner.py
/utest/new_running/test_running.py
=======================================
--- /src/robot/new_running/failures.py Fri May 24 00:45:38 2013
+++ /src/robot/new_running/failures.py Fri May 24 06:50:08 2013
@@ -13,35 +13,70 @@
# limitations under the License.
-class TestFailures(object):
+class ExecutionStatus(object):
- def __init__(self):
+ def __init__(self, parent_status=None):
+ self.parent_status = parent_status
self.setup_failure = None
self.test_failure = None
self.teardown_failure = None
+ self.teardown_allowed = False
+
+ def setup_executed(self, failure=None):
+ if failure:
+ self.setup_failure = unicode(failure)
+ self.teardown_allowed = True
+
+ def test_failed(self, failure):
+ self.test_failure = unicode(failure)
+
+ def teardown_executed(self, failure=None):
+ if failure:
+ self.teardown_failure = unicode(failure)
@property
- def run_allowed(self):
- return self.setup_failure is None
+ def message(self):
+ if self.parent_status and self.parent_status.failures:
+ return ParentMessageCreator(self.parent_status).create()
+ return MessageCreator(self).create()
@property
- def message(self):
+ def failures(self):
+ return bool(self.parent_status and self.parent_status.failures or
+ self.setup_failure or
+ self.test_failure or
+ self.teardown_failure)
+
+
+# TODO: Messages below are not identical to old run messages!!
+# Remember to also update messages in SuiteTeardownFailureHandler
+
+class MessageCreator(object):
+ setup_failed = 'Setup failed:\n%s'
+ teardown_failed = 'Teardown failed:\n%s'
+ also_teardown_failed = '%s\n\nAlso teardown failed:\n%s'
+
+ def __init__(self, status):
+ self.setup = status.setup_failure
+ self.test = status.test_failure or ''
+ self.teardown = status.teardown_failure
+
+ def create(self):
msg = self._get_message_before_teardown()
return self._get_message_after_teardown(msg)
def _get_message_before_teardown(self):
- if self.setup_failure is not None:
- return 'Setup failed:\n%s' % self.setup_failure
- return self.test_failure or ''
+ if self.setup:
+ return self.setup_failed % self.setup
+ return self.test
def _get_message_after_teardown(self, msg):
- if self.teardown_failure is None:
+ if not self.teardown:
return msg
if not msg:
- return 'Teardown failed:\n%s' % self.teardown_failure
- return '%s\n\nAlso teardown failed:\n%s' % (msg,
self.teardown_failure)
+ return self.teardown_failed % self.teardown
+ return self.also_teardown_failed % (msg, self.teardown)
+
- def __nonzero__(self):
- return (self.setup_failure is not None or
- self.test_failure is not None or
- self.teardown_failure is not None)
+class ParentMessageCreator(MessageCreator):
+ setup_failed = 'Parent suite setup failed:\n%s'
=======================================
--- /src/robot/new_running/runner.py Fri May 24 00:45:38 2013
+++ /src/robot/new_running/runner.py Fri May 24 06:50:08 2013
@@ -19,12 +19,11 @@
from robot.variables import GLOBAL_VARIABLES
from robot.running.context import EXECUTION_CONTEXTS
from robot.running.keywords import Keywords, Keyword
-from robot.running.fixture import Setup, Teardown
from robot.running.userkeyword import UserLibrary
from robot.errors import ExecutionFailed, DataError
from robot import utils
-from .failures import TestFailures
+from .failures import ExecutionStatus
class Runner(SuiteVisitor):
@@ -33,6 +32,7 @@
self.result = None
self._output = output
self._suite = None
+ self._suite_status = None
@property
def _context(self):
@@ -61,19 +61,24 @@
self.result = Result(root_suite=result)
else:
self._suite.suites.append(result)
+ self._suite_status = ExecutionStatus(self._suite_status)
self._suite = result
self._output.start_suite(self._suite)
- self._setup(suite.keywords.setup).run(self._context)
+ self._run_setup(suite.keywords.setup, self._suite_status)
def _resolve_setting(self, value):
value = self._variables.replace_string(value, ignore_errors=True)
return utils.unescape(value)
def end_suite(self, suite):
- self._teardown(suite.keywords.teardown).run(self._context)
+ failure = self._run_teardown(suite.keywords.teardown,
self._suite_status)
+ if failure:
+ self._suite.suite_teardown_failed(unicode(failure))
self._suite.endtime = utils.get_timestamp()
+ self._suite.message = self._suite_status.message
self._context.end_suite(self._suite)
self._suite = self._suite.parent
+ self._suite_status = self._suite_status.parent_status
def visit_test(self, test):
result = self._suite.tests.create(name=test.name,
@@ -87,28 +92,29 @@
if test.timeout:
test.timeout.replace_variables(self._variables) # FIXME:
Should not change model state!!
test.timeout.start()
- failures = TestFailures()
- self._run_test_setup(test.keywords.setup, failures)
+ status = ExecutionStatus(self._suite_status)
+ if not status.failures:
+ self._run_setup(test.keywords.setup, status)
try:
- if failures.run_allowed:
+ if not status.failures:
keywords.run(self._context)
except ExecutionFailed, err:
- failures.test_failure = unicode(err)
- self._run_test_teardown(test.keywords.teardown, failures)
- result.message = failures.message
- result.status = 'FAIL' if failures else 'PASS'
+ status.test_failed(err)
+ if status.teardown_allowed:
+ self._run_teardown(test.keywords.teardown, status)
+ result.message = status.message
+ result.status = 'FAIL' if status.failures else 'PASS'
result.endtime = utils.get_timestamp()
self._context.end_test(result)
- def _run_test_setup(self, setup, failures):
+ def _run_setup(self, setup, failures):
failure = self._run_setup_or_teardown(setup, 'setup')
- if failure is not None:
- failures.setup_failure = failure
+ failures.setup_executed(failure)
- def _run_test_teardown(self, teardown, failures):
+ def _run_teardown(self, teardown, failures):
failure = self._run_setup_or_teardown(teardown, 'teardown')
- if failure is not None:
- failures.teardown_failure = failure
+ failures.teardown_executed(failure)
+ return failure
def _run_setup_or_teardown(self, data, type):
if not data:
@@ -116,23 +122,9 @@
try:
name = self._variables.replace_string(data.name)
except DataError, err:
- return unicode(err)
+ return err
kw = Keyword(name, data.args, type=type)
try:
kw.run(self._context)
except ExecutionFailed, err:
- return unicode(err)
-
- def _setup(self, setup):
- if not setup:
- return Setup('', ())
- setup = Setup(setup.name, setup.args)
- setup.replace_variables(self._variables, [])
- return setup
-
- def _teardown(self, teardown):
- if not teardown:
- return Teardown('', ())
- teardown = Teardown(teardown.name, teardown.args)
- teardown.replace_variables(self._variables, [])
- return teardown
+ return err
=======================================
--- /utest/new_running/test_running.py Fri May 24 00:45:38 2013
+++ /utest/new_running/test_running.py Fri May 24 06:50:08 2013
@@ -10,18 +10,20 @@
DATADIR = normpath(join(CURDIR, '..', '..', 'atest', 'testdata', 'misc'))
-def run(suite):
- result = suite.run(output='NONE', stdout=StringIO(), stderr=StringIO())
+def run(suite, **kwargs):
+ result = suite.run(output='NONE', stdout=StringIO(), stderr=StringIO(),
+ **kwargs)
return result.suite
-def build_and_run(path):
- return run(TestSuiteBuilder().build(join(DATADIR, path)))
+def build(path):
+ return TestSuiteBuilder().build(join(DATADIR, path))
-def assert_suite(suite, name, status, tests=1):
+def assert_suite(suite, name, status, message='', tests=1):
assert_equals(suite.name, name)
assert_equals(suite.status, status)
+ assert_equals(suite.message, message)
assert_equals(len(suite.tests), tests)
@@ -100,10 +102,10 @@
assert_test(result.tests[1], 'T2', 'FAIL', ('added tag',), 'Error')
-class TestSetupAndTeardown(unittest.TestCase):
+class TestTestSetupAndTeardown(unittest.TestCase):
def setUp(self):
- self.tests = build_and_run('setups_and_teardowns.txt').tests
+ self.tests = run(build('setups_and_teardowns.txt')).tests
def test_passing_setup_and_teardown(self):
assert_test(self.tests[0], 'Test with setup and teardown', 'PASS')
@@ -119,3 +121,59 @@
def test_failing_test_with_failing_teardown(self):
assert_test(self.tests[3], 'Failing test with failing
teardown', 'FAIL',
msg='Keyword\n\nAlso teardown failed:\nTest Teardown')
+
+
+class TestSuiteSetupAndTeardown(unittest.TestCase):
+
+ def setUp(self):
+ self.suite = build('setups_and_teardowns.txt')
+
+ def test_passing_setup_and_teardown(self):
+ suite = run(self.suite)
+ assert_suite(suite, 'Setups And Teardowns', 'FAIL', tests=4)
+ assert_test(suite.tests[0], 'Test with setup and teardown', 'PASS')
+
+ def test_failing_setup(self):
+ suite = run(self.suite, variable='SUITE SETUP:Fail')
+ assert_suite(suite, 'Setups And Teardowns', 'FAIL',
+ 'Setup failed:\nAssertionError', 4)
+ assert_test(suite.tests[0], 'Test with setup and teardown', 'FAIL',
+ msg='Parent suite setup failed:\nAssertionError')
+
+ # TODO: Messages are inconsistent because suite teardown messages in
+ # tests come from old SuiteTeardownFailed. Change when new run
integrated!
+
+ def test_failing_teardown(self):
+ suite = run(self.suite, variable='SUITE TEARDOWN:Fail')
+ assert_suite(suite, 'Setups And Teardowns', 'FAIL',
+ 'Teardown failed:\nAssertionError', 4)
+ assert_test(suite.tests[0], 'Test with setup and teardown', 'FAIL',
+ msg='Teardown of the parent suite
failed:\nAssertionError')
+
+ def test_failing_test_with_failing_teardown(self):
+ suite = run(self.suite, variable=['SUITE SETUP:Fail', 'SUITE
TEARDOWN:Fail'])
+ assert_suite(suite, 'Setups And Teardowns', 'FAIL',
+ 'Setup failed:\nAssertionError\n\n'
+ 'Also teardown failed:\nAssertionError', 4)
+ assert_test(suite.tests[0], 'Test with setup and teardown', 'FAIL',
+ msg='Parent suite setup failed:\nAssertionError\n\n'
+ 'Also teardown of the parent suite
failed:\nAssertionError')
+
+ def test_nested_setups_and_teardowns(self):
+ root = TestSuite(name='Root')
+ root.keywords.create('Fail', ['Top level'], type='teardown')
+ root.suites.append(self.suite)
+ suite = run(root, variable=['SUITE SETUP:Fail', 'SUITE
TEARDOWN:Fail'])
+ assert_suite(suite, 'Root', 'FAIL',
+ 'Teardown failed:\nTop level', 0)
+ assert_suite(suite.suites[0], 'Setups And Teardowns', 'FAIL',
+ 'Setup failed:\nAssertionError\n\n'
+ 'Also teardown failed:\nAssertionError', 4)
+ assert_test(suite.suites[0].tests[0], 'Test with setup and
teardown', 'FAIL',
+ msg='Parent suite setup failed:\nAssertionError\n\n'
+ 'Also teardown of the parent suite
failed:\nAssertionError\n\n'
+ 'Also teardown of the parent suite failed:\nTop
level')
+
+
+if __name__ == '__main__':
+ unittest.main()
==============================================================================
Revision: 10f3837ff4a8
Branch: default
Author: Pekka Klärck
Date: Fri May 24 06:50:12 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=10f3837ff4a8
--
---
You received this message because you are subscribed to the Google Groups "robotframework-commit" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.