3 new revisions:
Revision: 97729dbc11e8
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 11:24:27 2014 UTC
Log: ItemList: added __setitem__
http://code.google.com/p/robotframework/source/detail?r=97729dbc11e8
Revision: 94832c7c8fb6
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 15:30:44 2014 UTC
Log: --rerunmerge option to Rebot...
http://code.google.com/p/robotframework/source/detail?r=94832c7c8fb6
Revision: db8dbe61aa26
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 15:30:52 2014 UTC
Log: Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=db8dbe61aa26
==============================================================================
Revision: 97729dbc11e8
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 11:24:27 2014 UTC
Log: ItemList: added __setitem__
http://code.google.com/p/robotframework/source/detail?r=97729dbc11e8
Modified:
/src/robot/model/itemlist.py
/utest/model/test_itemlist.py
=======================================
--- /src/robot/model/itemlist.py Thu Jan 23 14:00:53 2014 UTC
+++ /src/robot/model/itemlist.py Wed Jan 29 11:24:27 2014 UTC
@@ -67,6 +67,15 @@
% type(self).__name__)
return self._items[index]
+ def __setitem__(self, index, item):
+ if isinstance(index, slice):
+ raise TypeError("'%s' objects do not support slicing."
+ % type(self).__name__)
+ self._check_type_and_set_attrs(item)
+ items = list(self._items)
+ items[index] = item
+ self._items = tuple(items)
+
def __len__(self):
return len(self._items)
=======================================
--- /utest/model/test_itemlist.py Tue Aug 27 19:34:18 2013 UTC
+++ /utest/model/test_itemlist.py Wed Jan 29 11:24:27 2014 UTC
@@ -66,6 +66,20 @@
assert_equal(items.index('first'), 0)
assert_equal(items.index('second'), 1)
+ def test_setitem(self):
+ orig1, orig2 = Object(), Object()
+ new1, new2 = Object(), Object()
+ items = ItemList(Object, {'attr': 2}, [orig1, orig2])
+ items[0] = new1
+ assert_equal(list(items), [new1, orig2])
+ assert_equal(new1.attr, 2)
+ items[-1] = new2
+ assert_equal(list(items), [new1, new2])
+ assert_equal(new2.attr, 2)
+
+ def test_setitem_slice_is_not_supported(self):
+ assert_raises(TypeError, ItemList(int).__setitem__, slice(0))
+
def test_len(self):
items = ItemList(object)
assert_equal(len(items), 0)
==============================================================================
Revision: 94832c7c8fb6
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 15:30:44 2014 UTC
Log: --rerunmerge option to Rebot
Update issue 1615
Status: Started
Owner: pekka.klarck
Implementation and tests done. Could still add some tests for handling other
options with --ReRunMerge, especially options that are passed to underlying
ExecutionResultBuilder.
Documentation needed:
1) --help text (TODO added)
2) doc string update for ExecutionResult (TODO added)
3) User Guide
http://code.google.com/p/robotframework/source/detail?r=94832c7c8fb6
Added:
/atest/robot/rebot/rerun_merge.txt
/src/robot/result/rerunmerger.py
Modified:
/atest/resources/TestCheckerLibrary.py
/src/robot/conf/settings.py
/src/robot/rebot.py
/src/robot/reporting/resultwriter.py
/src/robot/result/resultbuilder.py
=======================================
--- /dev/null
+++ /atest/robot/rebot/rerun_merge.txt Wed Jan 29 15:30:44 2014 UTC
@@ -0,0 +1,131 @@
+*** Settings ***
+Force Tags regression pybot jybot
+Suite Setup Run original tests
+Suite Teardown Remove Files ${ORIGINAL} ${RERUN} ${RERUN 2}
+Resource rebot_resource.txt
+
+*** Variables ***
+${TEST CASES} ${DATADIR}/misc/suites
+${ORIGINAL} %{TEMPDIR}/merge-original.xml
+${RERUN} %{TEMPDIR}/merge-rerun.xml
+${RERUN 2} %{TEMPDIR}/merge-rerun-2.xml
+@{ALL TESTS} Suite4 First SubSuite1 First SubSuite2
First
+... Test From Sub Suite 4 SubSuite3 First SubSuite3
Second
+... Suite1 First Suite1 Second Third In
Suite1
+... Suite2 First Suite3 First
+@{ALL SUITES} Fourth Subsuites Subsuites2
+... Tsuite1 Tsuite2 Tsuite3
+@{SUB SUITES 1} Sub1 Sub2
+@{SUB SUITES 2} Sub.suite.4 Subsuite3
+@{RERUN TESTS} Suite4 First SubSuite1 First
+@{RERUN SUITES} Fourth Subsuites
+
+*** Test Cases ***
+Successful merge
+ Rerun tests
+ Run merge
+ Merge should have been successful
+
+Successful multi-merge
+ Rerun tests
+ Rerun tests again
+ Run multi-merge
+ ${message} = Create expected multi-merge message
+ Merge should have been successful status 2=FAIL message
2=${message}
+
+Non-matching root suite
+ Create output with incompatible root suite
+ Run merge
+ Stderr Should Be Equal To
+ ... [ ERROR ] Merged suite 'Incompatible' is ignored because it is
not found from original result.\n
+ Verify original tests
+
+Non-matching child suite
+ Create output with incompatible child suite
+ Run merge
+ Stderr Should Be Equal To SEPARATOR=
+ ... [ ERROR ] Merged suite 'Suites.Sub1' is ignored because it is
not found from original result.\n
+ ... [ ERROR ] Merged suite 'Suites.Sub2' is ignored because it is
not found from original result.\n
+ Verify original tests
+
+Non-matching test
+ Create output with incompatible test
+ Run merge
+ Stderr Should Be Equal To
+ ... [ ERROR ] Merged test 'Suites.Fourth.Non-existing' is ignored
because it is not found from original result.\n
+ Merge should have been successful message 1=Expected
+
+*** Keywords **
+Run original tests
+ Create Output With Robot ${ORIGINAL} --variable FAIL:YES
${TEST CASES}
+ Verify original tests
+
+Verify original tests
+ Should Be Equal ${SUITE.name} Suites
+ Should Contain Suites ${SUITE} @{ALL SUITES}
+ Should Contain Suites ${SUITE.suites[1]} @{SUB SUITES 1}
+ Should Contain Suites ${SUITE.suites[2]} @{SUB SUITES 2}
+ Check Suite Contains Tests ${SUITE} @{ALL TESTS}
+ ... SubSuite1 First=FAIL:This test was doomed to fail: YES != NO
+
+Rerun tests
+ Create Output With Robot ${RERUN} --runfailed ${ORIGINAL}
${TEST CASES}
+ Should Be Equal ${SUITE.name} Suites
+ Should Contain Suites ${SUITE} @{RERUN SUITES}
+ Should Contain Suites ${SUITE.suites[1]} @{SUB SUITES 1}[0]
+ Check Suite Contains Tests ${SUITE} @{RERUN TESTS}
+
+Rerun tests again
+ Create Output With Robot ${RERUN 2} --test SubSuite1First
--variable FAIL:again ${TEST CASES}
+
+Create output with incompatible root suite
+ Create Output With Robot ${RERUN} --name Incompatible --test
SubSuite1First ${TEST CASES}
+
+Create output with incompatible child suite
+ Create Output With Robot ${RERUN} --name Suites ${TEST
CASES}/subsuites
+
+Create output with incompatible test
+ Rerun tests
+ ${xml} = Parse XML ${RERUN}
+ Log Element ${xml}
+ Set Element Attribute ${xml} name Non-existing
xpath=suite/suite/test
+ Save XML ${xml} ${RERUN}
+
+Run merge
+ Run Rebot --rerunmerge ${ORIGINAL} ${RERUN}
+
+Run multi-merge
+ Run Rebot -R ${ORIGINAL} ${RERUN} ${RERUN 2}
+
+Merge should have been successful
+ [Arguments] ${status 1}=FAIL ${message 1}= ${status
2}=PASS ${message 2}=
+ Should Be Equal ${SUITE.name} Suites
+ Should Contain Suites ${SUITE} @{ALL SUITES}
+ Should Contain Suites ${SUITE.suites[1]} @{SUB SUITES 1}
+ Should Contain Suites ${SUITE.suites[2]} @{SUB SUITES 2}
+ ${message 1} = Create expected merge message ${message 1}
+ ... FAIL Expected FAIL Expected
+ ${message 2} = Create expected merge message ${message 2}
+ ... PASS ${EMPTY} FAIL This test was doomed to fail:
YES != NO
+ Check Suite Contains Tests ${SUITE} @{ALL TESTS}
+ ... Suite4 First=${status 1}:${message 1}
+ ... SubSuite1 First=${status 2}:${message 2}
+
+Create expected merge message
+ [Arguments] ${message} ${new status} ${new message} ${old
status} ${old message}
+ Return From Keyword If """${message}""" ${message}
+ Run Keyword And Return Catenate SEPARATOR=\n
+ ... Test has been re-run and results replaced.
+ ... - \ - \ -
+ ... New status: \ ${new status}
+ ... New message: \ ${new message}
+ ... - \ - \ -
+ ... Old status: \ ${old status}
+ ... Old message: \ ${old message}
+
+Create expected multi-merge message
+ ${message} = Create expected merge message ${EMPTY}
+ ... PASS ${EMPTY} FAIL This test was doomed to fail:
YES != NO
+ ${message} = Create expected merge message ${EMPTY}
+ ... FAIL This test was doomed to fail: again != NO PASS
${message}
+ [Return] ${message}
=======================================
--- /dev/null
+++ /src/robot/result/rerunmerger.py Wed Jan 29 15:30:44 2014 UTC
@@ -0,0 +1,74 @@
+# Copyright 2008-2014 Nokia Solutions and Networks
+#
+# 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.
+
+from robot.model import SuiteVisitor
+
+
+class ReRunMerger(SuiteVisitor):
+
+ def __init__(self, result):
+ self.root = result.suite
+ self.current = None
+
+ def merge(self, merged):
+ merged.suite.visit(self)
+
+ def start_suite(self, suite):
+ try:
+ if not self.current:
+ self.current = self._find_root(suite)
+ else:
+ self.current = self._find(self.current.suites, suite.name)
+ except ValueError:
+ self._report_ignored(suite)
+ return False
+
+ def _find_root(self, suite):
+ if self.root.name != suite.name:
+ raise ValueError
+ return self.root
+
+ def _find(self, items, name):
+ for item in items:
+ if item.name == name:
+ return item
+ raise ValueError
+
+ def _report_ignored(self, item, test=False):
+ from robot.output import LOGGER
+ type = 'suite' if not test else 'test'
+ LOGGER.error("Merged %s '%s' is ignored because it is not found
from "
+ "original result." % (type, item.longname))
+
+ def end_suite(self, suite):
+ self.current = self.current.parent
+
+ def visit_test(self, test):
+ try:
+ old = self._find(self.current.tests, test.name)
+ except ValueError:
+ self._report_ignored(test, test=True)
+ else:
+ test.message = self._create_merge_message(test, old)
+ index = self.current.tests.index(old)
+ self.current.tests[index] = test
+
+ def _create_merge_message(self, new, old):
+ return '\n'.join(['Test has been re-run and results replaced.',
+ '- - -',
+ 'New status: %s' % new.status,
+ 'New message: %s' % new.message,
+ '- - -',
+ 'Old status: %s' % old.status,
+ 'Old message: %s' % old.message])
=======================================
--- /atest/resources/TestCheckerLibrary.py Wed Jun 5 20:01:38 2013 UTC
+++ /atest/resources/TestCheckerLibrary.py Wed Jan 29 15:30:44 2014 UTC
@@ -106,19 +106,26 @@
"Expected:\n%s\n\nActual:\n%s\n"
% (test.exp_message, test.message))
- def check_suite_contains_tests(self, suite, *expected_names):
+ def check_suite_contains_tests(self, suite, *expected_names,
**statuses):
actual_tests = [test for test in self.get_tests_from_suite(suite)]
- tests_msg = """
+ tests_msg = """
Expected tests : %s
-Actual tests : %s""" % (str(list(expected_names)), str(actual_tests))
+Actual tests : %s""" % (str(list(expected_names)), str(actual_tests))
expected_names = [utils.normalize(name) for name in expected_names]
+ statuses = dict((utils.normalize(k), v) for k, v in
statuses.items())
if len(actual_tests) != len(expected_names):
raise AssertionError("Wrong number of tests." + tests_msg)
for test in actual_tests:
+ norm_name = utils.normalize(test.name)
if utils.MultiMatcher(expected_names).match(test.name):
print "Verifying test '%s'" % test.name
- self.check_test_status(test)
- expected_names.remove(utils.normalize(test.name))
+ status = statuses.get(norm_name)
+ if status and ':' in status:
+ status, message = status.split(':', 1)
+ else:
+ message = None
+ self.check_test_status(test, status, message)
+ expected_names.remove(norm_name)
else:
raise AssertionError("Test '%s' was not expected to be
run.%s"
% (test.name, tests_msg))
=======================================
--- /src/robot/conf/settings.py Wed Jan 29 10:52:58 2014 UTC
+++ /src/robot/conf/settings.py Wed Jan 29 15:30:44 2014 UTC
@@ -458,7 +458,8 @@
'LogLevel' : ('loglevel', 'TRACE'),
'ProcessEmptySuite' : ('processemptysuite', False),
'StartTime' : ('starttime', None),
- 'EndTime' : ('endtime', None)}
+ 'EndTime' : ('endtime', None),
+ 'ReRunMerge' : ('rerunmerge', False)}
def _output_disabled(self):
return False
@@ -512,6 +513,10 @@
def _resolve_background_colors(self):
colors = self['ReportBackground']
return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail':
colors[2]}
+
+ @property
+ def rerun_merge(self):
+ return self['ReRunMerge']
@property
def console_logger_config(self):
=======================================
--- /src/robot/rebot.py Sat Jan 25 23:51:09 2014 UTC
+++ /src/robot/rebot.py Wed Jan 29 15:30:44 2014 UTC
@@ -93,6 +93,7 @@
tests are not selected even if included with
--include. Tags are matched using the rules
explained
with --include.
+ -R --rerunmerge *** TODO ***
--processemptysuite Processes output also if the top level test
suite is
empty. Useful e.g. with --include/--exclude when
it
is not an error that no test matches the
condition.
=======================================
--- /src/robot/reporting/resultwriter.py Thu Jan 23 14:00:53 2014 UTC
+++ /src/robot/reporting/resultwriter.py Wed Jan 29 15:30:44 2014 UTC
@@ -114,8 +114,10 @@
if self._result is None:
include_keywords = bool(self._settings.log or
self._settings.output)
flattened = self._settings.flatten_keywords
+ rerun_merge = self._settings.rerun_merge
self._result =
ExecutionResult(include_keywords=include_keywords,
flattened_keywords=flattened,
+ rerun_merge=rerun_merge,
*self._sources)
self._result.configure(self._settings.status_rc,
self._settings.suite_config,
=======================================
--- /src/robot/result/resultbuilder.py Thu Jan 23 14:00:53 2014 UTC
+++ /src/robot/result/resultbuilder.py Wed Jan 29 15:30:44 2014 UTC
@@ -19,6 +19,7 @@
from .executionresult import Result, CombinedResult
from .flattenkeywordmatcher import FlattenKeywordMatcher
+from .rerunmerger import ReRunMerger
from .xmlelementhandlers import XmlElementHandler
@@ -28,18 +29,30 @@
:param sources: Path(s) to output XML file(s).
:param options: Configuration options passed to
:py:class:`~ExecutionResultBuilder` as keyword
arguments.
+ *** TODO ***
:returns: :class:`~.executionresult.Result` instance.
See :mod:`~robot.result` package for a usage example.
"""
if not sources:
raise DataError('One or more data source needed.')
+ if options.pop('rerun_merge', False):
+ return _rerun_merge_results(sources[0], sources[1:], options)
if len(sources) > 1:
- return _combined_result(sources, options)
+ return _combine_results(sources, options)
return _single_result(sources[0], options)
-def _combined_result(sources, options):
+def _rerun_merge_results(original, merged, options):
+ result = ExecutionResult(original, **options)
+ merger = ReRunMerger(result)
+ for path in merged:
+ merged = ExecutionResult(path, **options)
+ merger.merge(merged)
+ return result
+
+
+def _combine_results(sources, options):
return CombinedResult(ExecutionResult(src, **options) for src in
sources)
==============================================================================
Revision: db8dbe61aa26
Branch: default
Author: Robot Framework Developers (robotframew...@gmail.com)
Date: Wed Jan 29 15:30:52 2014 UTC
Log: Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=db8dbe61aa26
--
---
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 robotframework-commit+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.