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.


Reply via email to