6 new revisions:
Revision: 271c1b302f10
Branch: default
Author: Pekka Klärck
Date: Wed May 22 16:16:28 2013
Log: typo fixes in ug
http://code.google.com/p/robotframework/source/detail?r=271c1b302f10
Revision: 314a93cdd952
Branch: default
Author: Pekka Klärck
Date: Thu May 23 23:24:44 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=314a93cdd952
Revision: d7433e308cc0
Branch: default
Author: Pekka Klärck
Date: Thu May 23 23:32:42 2013
Log: refactored utests to ease creating new suites into same module
http://code.google.com/p/robotframework/source/detail?r=d7433e308cc0
Revision: b0cb30011848
Branch: default
Author: Pekka Klärck
Date: Fri May 24 00:45:38 2013
Log: new run: handle failures in test setup/teardown
http://code.google.com/p/robotframework/source/detail?r=b0cb30011848
Revision: 7ad690543152
Branch: default
Author: Pekka Klärck
Date: Fri May 24 02:51:16 2013
Log: Fixed handling using non-existing variables in variable table....
http://code.google.com/p/robotframework/source/detail?r=7ad690543152
Revision: c067ab3b5b43
Branch: default
Author: Pekka Klärck
Date: Fri May 24 02:51:25 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=c067ab3b5b43
==============================================================================
Revision: 271c1b302f10
Branch: default
Author: Pekka Klärck
Date: Wed May 22 16:16:28 2013
Log: typo fixes in ug
http://code.google.com/p/robotframework/source/detail?r=271c1b302f10
Modified:
/doc/userguide/src/CreatingTestData/CreatingTestCases.rst
/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.rst
=======================================
--- /doc/userguide/src/CreatingTestData/CreatingTestCases.rst Wed May 8
00:42:06 2013
+++ /doc/userguide/src/CreatingTestData/CreatingTestCases.rst Wed May 22
16:16:28 2013
@@ -255,8 +255,8 @@
their default values.
In Robot Framework 2.8 support for using named argument syntax for
-arguments without default values was added. Also possiblity to use named
-argument syntax with Python keywords that take keyworded variable
`**kwargs`
+arguments without default values was added. Also possibility to use named
+argument syntax with Python keywords that take keyword arguments `**kwargs`
was added.
=======================================
--- /doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.rst
Tue Apr 16 15:01:58 2013
+++ /doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.rst
Wed May 22 16:16:28 2013
@@ -1291,7 +1291,7 @@
This is especially important when threads are run on background while
other keywords are running. Results of communicating with the
-framework in that case are undefined and can in works case cause a
+framework in that case are undefined and can in the worst case cause a
crash or a corrupted output file. If a keyword starts something on
background, there should be another keyword that checks the status of
the worker thread and reports gathered information accordingly.
==============================================================================
Revision: 314a93cdd952
Branch: default
Author: Pekka Klärck
Date: Thu May 23 23:24:44 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=314a93cdd952
==============================================================================
Revision: d7433e308cc0
Branch: default
Author: Pekka Klärck
Date: Thu May 23 23:32:42 2013
Log: refactored utests to ease creating new suites into same module
http://code.google.com/p/robotframework/source/detail?r=d7433e308cc0
Modified:
/utest/new_running/test_running.py
=======================================
--- /utest/new_running/test_running.py Wed May 22 02:44:45 2013
+++ /utest/new_running/test_running.py Thu May 23 23:32:42 2013
@@ -5,61 +5,79 @@
from robot.new_running import TestSuite
+def run(suite):
+ result = suite.run(output='NONE', stdout=StringIO(), stderr=StringIO())
+ return result.suite
+
+
+def assert_suite(suite, name, status, tests=1):
+ assert_equals(suite.name, name)
+ assert_equals(suite.status, status)
+ assert_equals(len(suite.tests), tests)
+
+
+def assert_test(test, name, status, tags=(), msg=''):
+ assert_equals(test.name, name)
+ assert_equals(test.status, status)
+ assert_equals(test.message, msg)
+ assert_equals(tuple(test.tags), tags)
+
+
class TestRunning(unittest.TestCase):
def test_one_library_keyword(self):
suite = TestSuite(name='Suite')
suite.tests.create(name='Test').keywords.create('Log',
args=['Hello,
world!'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'PASS')
- self._check_test(result.tests[0], 'Test', 'PASS')
+ result = run(suite)
+ assert_suite(result, 'Suite', 'PASS')
+ assert_test(result.tests[0], 'Test', 'PASS')
def test_failing_library_keyword(self):
suite = TestSuite(name='Suite')
test = suite.tests.create(name='Test')
test.keywords.create('Log', args=['Dont fail yet.'])
test.keywords.create('Fail', args=['Hello, world!'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'FAIL')
- self._check_test(result.tests[0], 'Test', 'FAIL', msg='Hello,
world!')
+ result = run(suite)
+ assert_suite(result, 'Suite', 'FAIL')
+ assert_test(result.tests[0], 'Test', 'FAIL', msg='Hello, world!')
def test_assign(self):
suite = TestSuite(name='Suite')
test = suite.tests.create(name='Test')
test.keywords.create(assign=['${var}'], name='Set Variable',
args=['value in variable'])
test.keywords.create('Fail', args=['${var}'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'FAIL')
- self._check_test(result.tests[0], 'Test', 'FAIL', msg='value in
variable')
+ result = run(suite)
+ assert_suite(result, 'Suite', 'FAIL')
+ assert_test(result.tests[0], 'Test', 'FAIL', msg='value in
variable')
def test_suites_in_suites(self):
root = TestSuite(name='Root')
root.suites.create(name='Child')\
.tests.create(name='Test')\
.keywords.create('Log', args=['Hello, world!'])
- result = self._run(root)
- self._check_suite(result, 'Root', 'PASS', tests=0)
- self._check_suite(result.suites[0], 'Child', 'PASS')
- self._check_test(result.suites[0].tests[0], 'Test', 'PASS')
+ result = run(root)
+ assert_suite(result, 'Root', 'PASS', tests=0)
+ assert_suite(result.suites[0], 'Child', 'PASS')
+ assert_test(result.suites[0].tests[0], 'Test', 'PASS')
def test_imports(self):
suite = TestSuite(name='Suite')
suite.imports.create('Library', 'OperatingSystem')
suite.tests.create(name='Test').keywords.create('Directory Should
Exist',
args=['.'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'PASS')
- self._check_test(result.tests[0], 'Test', 'PASS')
+ result = run(suite)
+ assert_suite(result, 'Suite', 'PASS')
+ assert_test(result.tests[0], 'Test', 'PASS')
def test_user_keywords(self):
suite = TestSuite(name='Suite')
suite.tests.create(name='Test').keywords.create('User keyword',
args=['From uk'])
uk = suite.user_keywords.create(name='User keyword',
args=['${msg}'])
uk.keywords.create(name='Fail', args=['${msg}'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'FAIL')
- self._check_test(result.tests[0], 'Test', 'FAIL', msg='From uk')
+ result = run(suite)
+ assert_suite(result, 'Suite', 'FAIL')
+ assert_test(result.tests[0], 'Test', 'FAIL', msg='From uk')
def test_variables(self):
suite = TestSuite(name='Suite')
@@ -67,22 +85,7 @@
suite.variables.create('@{LIST}', ['Error', 'added tag'])
suite.tests.create(name='T1').keywords.create('Fail',
args=['${ERROR}'])
suite.tests.create(name='T2').keywords.create('Fail',
args=['@{LIST}'])
- result = self._run(suite)
- self._check_suite(result, 'Suite', 'FAIL', tests=2)
- self._check_test(result.tests[0], 'T1', 'FAIL', msg='Error
message')
- self._check_test(result.tests[1], 'T2', 'FAIL', ('added
tag',), 'Error')
-
- def _run(self, suite):
- result = suite.run(output='NONE', stdout=StringIO(),
stderr=StringIO())
- return result.suite
-
- def _check_suite(self, suite, name, status, tests=1):
- assert_equals(suite.name, name)
- assert_equals(suite.status, status)
- assert_equals(len(suite.tests), tests)
-
- def _check_test(self, test, name, status, tags=(), msg=''):
- assert_equals(test.name, name)
- assert_equals(test.status, status)
- assert_equals(test.message, msg)
- assert_equals(tuple(test.tags), tags)
+ result = run(suite)
+ assert_suite(result, 'Suite', 'FAIL', tests=2)
+ assert_test(result.tests[0], 'T1', 'FAIL', msg='Error message')
+ assert_test(result.tests[1], 'T2', 'FAIL', ('added tag',), 'Error')
==============================================================================
Revision: b0cb30011848
Branch: default
Author: Pekka Klärck
Date: Fri May 24 00:45:38 2013
Log: new run: handle failures in test setup/teardown
http://code.google.com/p/robotframework/source/detail?r=b0cb30011848
Added:
/src/robot/new_running/failures.py
Modified:
/src/robot/new_running/runner.py
/utest/new_running/test_running.py
=======================================
--- /dev/null
+++ /src/robot/new_running/failures.py Fri May 24 00:45:38 2013
@@ -0,0 +1,47 @@
+# Copyright 2008-2012 Nokia Siemens Networks Oyj
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class TestFailures(object):
+
+ def __init__(self):
+ self.setup_failure = None
+ self.test_failure = None
+ self.teardown_failure = None
+
+ @property
+ def run_allowed(self):
+ return self.setup_failure is None
+
+ @property
+ def message(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 ''
+
+ def _get_message_after_teardown(self, msg):
+ if self.teardown_failure is None:
+ 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)
+
+ def __nonzero__(self):
+ return (self.setup_failure is not None or
+ self.test_failure is not None or
+ self.teardown_failure is not None)
=======================================
--- /src/robot/new_running/runner.py Wed May 22 15:27:57 2013
+++ /src/robot/new_running/runner.py Fri May 24 00:45:38 2013
@@ -18,12 +18,14 @@
from robot.running.namespace import Namespace
from robot.variables import GLOBAL_VARIABLES
from robot.running.context import EXECUTION_CONTEXTS
-from robot.running.keywords import Keywords
+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
+from robot.errors import ExecutionFailed, DataError
from robot import utils
+from .failures import TestFailures
+
class Runner(SuiteVisitor):
@@ -78,27 +80,49 @@
doc=self._resolve_setting(test.doc),
tags=test.tags,
starttime=utils.get_timestamp())
- setup = self._setup(test.keywords.setup)
keywords = Keywords(test.keywords.normal)
- teardown = self._teardown(test.keywords.teardown)
result.timeout = test.timeout # TODO: Cleaner implementation
to ...
result.status = 'RUNNING' # ... activate timeouts
self._context.start_test(result)
if test.timeout:
test.timeout.replace_variables(self._variables) # FIXME:
Should not change model state!!
test.timeout.start()
- setup.run(self._context)
+ failures = TestFailures()
+ self._run_test_setup(test.keywords.setup, failures)
try:
- keywords.run(self._context)
+ if failures.run_allowed:
+ keywords.run(self._context)
except ExecutionFailed, err:
- result.message = unicode(err)
- result.status = 'FAIL'
- else:
- result.status = 'PASS'
- teardown.run(self._context)
+ failures.test_failure = unicode(err)
+ self._run_test_teardown(test.keywords.teardown, failures)
+ result.message = failures.message
+ result.status = 'FAIL' if failures else 'PASS'
result.endtime = utils.get_timestamp()
self._context.end_test(result)
+ def _run_test_setup(self, setup, failures):
+ failure = self._run_setup_or_teardown(setup, 'setup')
+ if failure is not None:
+ failures.setup_failure = failure
+
+ def _run_test_teardown(self, teardown, failures):
+ failure = self._run_setup_or_teardown(teardown, 'teardown')
+ if failure is not None:
+ failures.teardown_failure = failure
+
+ def _run_setup_or_teardown(self, data, type):
+ if not data:
+ return None
+ try:
+ name = self._variables.replace_string(data.name)
+ except DataError, err:
+ return unicode(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('', ())
=======================================
--- /utest/new_running/test_running.py Thu May 23 23:32:42 2013
+++ /utest/new_running/test_running.py Fri May 24 00:45:38 2013
@@ -1,8 +1,13 @@
import unittest
from StringIO import StringIO
+from os.path import abspath, dirname, normpath, join
from robot.utils.asserts import assert_equals
-from robot.new_running import TestSuite
+from robot.new_running import TestSuite, TestSuiteBuilder
+
+
+CURDIR = dirname(abspath(__file__))
+DATADIR = normpath(join(CURDIR, '..', '..', 'atest', 'testdata', 'misc'))
def run(suite):
@@ -10,6 +15,10 @@
return result.suite
+def build_and_run(path):
+ return run(TestSuiteBuilder().build(join(DATADIR, path)))
+
+
def assert_suite(suite, name, status, tests=1):
assert_equals(suite.name, name)
assert_equals(suite.status, status)
@@ -89,3 +98,24 @@
assert_suite(result, 'Suite', 'FAIL', tests=2)
assert_test(result.tests[0], 'T1', 'FAIL', msg='Error message')
assert_test(result.tests[1], 'T2', 'FAIL', ('added tag',), 'Error')
+
+
+class TestSetupAndTeardown(unittest.TestCase):
+
+ def setUp(self):
+ self.tests = build_and_run('setups_and_teardowns.txt').tests
+
+ def test_passing_setup_and_teardown(self):
+ assert_test(self.tests[0], 'Test with setup and teardown', 'PASS')
+
+ def test_failing_setup(self):
+ assert_test(self.tests[1], 'Test with failing setup', 'FAIL',
+ msg='Setup failed:\nTest Setup')
+
+ def test_failing_teardown(self):
+ assert_test(self.tests[2], 'Test with failing teardown', 'FAIL',
+ msg='Teardown failed:\nTest Teardown')
+
+ 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')
==============================================================================
Revision: 7ad690543152
Branch: default
Author: Pekka Klärck
Date: Fri May 24 02:51:16 2013
Log: Fixed handling using non-existing variables in variable table.
Update issue 561
Summary: Not possible to use imported variables in variable table
Labels: Type-Defect
Status: Done
The problem with non-existing variables is now fixed. I'm really surprised
there were no tests for this earlier.
Also changed the type of this issue from enhancement to defect. I don't
think the earlier behavior was a feature.
http://code.google.com/p/robotframework/source/detail?r=7ad690543152
Modified:
/atest/robot/variables/variable_table.txt
/atest/testdata/variables/variable_table.txt
/src/robot/variables/variables.py
=======================================
--- /atest/robot/variables/variable_table.txt Wed Apr 17 05:42:46 2013
+++ /atest/robot/variables/variable_table.txt Fri May 24 02:51:16 2013
@@ -50,12 +50,44 @@
Check Test Case ${TEST NAME}
Using Scalar List Should Fail
- ${path}= Normalize Path ${DATADIR}/variables/variable_table.txt
- ${msg}= Catenate
- ... Error in file '${path}' in table 'Variables': Setting variable
- ... '\${SCALAR LIST}' failed: Creating a scalar variable with a list
- ... value in the Variable table is no longer possible. Create a list
- ... variable '\@{SCALAR LIST}' and use it as a scalar variable
- ... '\${SCALAR LIST}' instead.
Check Test Case ${TEST NAME}
- Check Log Message ${ERRORS[0]} ${msg} ERROR
+ Creating Variable Should Have Failed ${ERRORS[0]} \${SCALAR LIST}
+ ... Creating a scalar variable with a list value in the Variable
table
+ ... is no longer possible. Create a list variable '\@{SCALAR LIST}'
+ ... and use it as a scalar variable '\${SCALAR LIST}' instead.
+
+Creating variable using non-existing variable fails
+ Check Test Case ${TEST NAME}
+ Creating Variable Should Have Failed ${ERRORS[4]} \${NONEX 1}
+ ... Non-existing variable '\${NON EXISTING}'.
+ Creating Variable Should Have Failed ${ERRORS[5]} \${NONEX 2A}
+ ... Non-existing variable '\${NON EX}'.
+ Creating Variable Should Have Failed ${ERRORS[6]} \${NONEX 2B}
+ ... Non-existing variable '\${NONEX 2A}'.
+
+Using variable created from non-existing variable in imports fails
+ Creating Variable Should Have Failed ${ERRORS[1]} \${NONEX 3}
+ ... Non-existing variable '\${NON EXISTING VARIABLE}'.
+ Import Should Have Failed ${ERRORS[2]} Resource
+ ... Non-existing variable '\${NONEX 3}'.
+ Import Should Have Failed ${ERRORS[3]} Library
+ ... Non-existing variable '\${NONEX 3}'.
+
+*** Keywords ***
+Creating Variable Should Have Failed
+ [Arguments] ${error} ${name} @{message}
+ ${path} = Normalize Path ${DATADIR}/variables/variable_table.txt
+ ${msg} = Catenate
+ ... Error in file '${path}' in table 'Variables':
+ ... Setting variable '${name}' failed:
+ ... @{message}
+ Check Log Message ${error} ${msg} ERROR
+
+Import Should Have Failed
+ [Arguments] ${error} ${name} @{message}
+ ${path} = Normalize Path ${DATADIR}/variables/variable_table.txt
+ ${msg} = Catenate
+ ... Error in file '${path}' in table 'Settings':
+ ... Replacing variables from setting '${name}' failed:
+ ... @{message}
+ Check Log Message ${error} ${msg} ERROR
=======================================
--- /atest/testdata/variables/variable_table.txt Tue May 7 07:19:17 2013
+++ /atest/testdata/variables/variable_table.txt Fri May 24 02:51:16 2013
@@ -22,6 +22,14 @@
${THREE DOTS} ...
@{3DOTS LIST} ... ...
${SCALAR LIST} I am a scalar list with many
items
+${NONEX 1} Creating variable based on ${NON EXISTING} variable
fails.
+${NONEX 2A} This ${NON EX} is used for creating another variable.
+${NONEX 2B} ${NONEX 2A}
+${NONEX 3} This ${NON EXISTING VARIABLE} is used in imports.
+
+*** Settings ***
+Resource ${NONEX 3}
+Library ${NONEX 3}
*** Test Case ***
Scalar String
@@ -107,5 +115,10 @@
Should Be Equal ${sos} ...---...
Using Scalar List Should Fail
- [Documentation] FAIL Non-existing variable '${SCALAR LIST}'.
- Log ${SCALAR LIST}
+ Variable Should Not Exist ${SCALAR LIST}
+
+Creating variable using non-existing variable fails
+ Variable Should Not Exist ${NONEX 1}
+ Variable Should Not Exist ${NONEX 2A}
+ Variable Should Not Exist ${NONEX 2B}
+ Variable Should Not Exist ${NONEX 3}
=======================================
--- /src/robot/variables/variables.py Wed May 22 02:41:21 2013
+++ /src/robot/variables/variables.py Fri May 24 02:51:16 2013
@@ -90,12 +90,15 @@
def _solve_delayed(self, name, value):
if isinstance(value, DelayedVariable):
- value = value.resolve(name, self)
- self[name] = value
+ return value.resolve(name, self)
return value
def resolve_delayed(self):
- self.values()
+ for var in self:
+ try:
+ self[var] # getting variable indirectly resolves it if
needed
+ except DataError:
+ pass
def _validate_var_name(self, name):
if not is_var(name):
@@ -330,21 +333,24 @@
self.set(name, value)
def set_from_variable_table(self, variables, overwrite=False):
+ def report_invalid_syntax(name, error):
+ # TODO: Error reporting is disabled with new model
+ if not hasattr(variables, 'report_invalid_syntax'):
+ return
+ variables.report_invalid_syntax("Setting variable '%s'
failed: %s"
+ % (name, unicode(error)))
for var in variables:
if not var:
continue # TODO: Remove compatibility with old run model.
try:
name, value = self._get_var_table_name_and_value(
- var.name, var.value)
+ var.name, var.value, report_invalid_syntax)
if overwrite or not self.contains(name):
self.set(name, value)
except DataError, err:
- # TODO: Error reporting is disabled with new model
- if hasattr(variables, 'report_invalid_syntax'):
- variables.report_invalid_syntax("Setting variable '%s'
failed: %s"
- % (var.name,
unicode(err)))
+ report_invalid_syntax(var.name, err)
- def _get_var_table_name_and_value(self, name, value):
+ def _get_var_table_name_and_value(self, name, value, error_reporter):
self._validate_var_name(name)
# TODO: Old run gives as scalars as list, new as strings. Clean up!
if is_scalar_var(name) and isinstance(value, basestring):
@@ -352,7 +358,7 @@
else:
self._validate_var_is_not_scalar_list(name, value)
value = [self._unescape_leading_trailing_spaces(cell) for cell in
value]
- return name, DelayedVariable(value)
+ return name, DelayedVariable(value, error_reporter)
def _unescape_leading_trailing_spaces(self, item):
if item.endswith(' \\'):
@@ -419,10 +425,21 @@
class DelayedVariable(object):
- def __init__(self, value):
+ def __init__(self, value, error_reporter):
self._value = value
+ self._error_reporter = error_reporter
def resolve(self, name, variables):
+ try:
+ value = self._resolve(name, variables)
+ except DataError, err:
+ self._error_reporter(name, err)
+ variables.pop(name)
+ raise DataError("Non-existing variable '%s'." % name)
+ variables[name] = value
+ return value
+
+ def _resolve(self, name, variables):
if is_list_var(name):
return variables.replace_list(self._value)
return variables.replace_scalar(self._value[0])
==============================================================================
Revision: c067ab3b5b43
Branch: default
Author: Pekka Klärck
Date: Fri May 24 02:51:25 2013
Log: Automated merge with https://code.google.com/p/robotframework/
http://code.google.com/p/robotframework/source/detail?r=c067ab3b5b43
--
---
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.