2 new revisions:
Revision: 62d08391b1be
Author: Pekka Klärck
Date: Sun Dec 18 14:26:45 2011
Log: StringCache: No need to keep count on an index when it is the
same as ...
http://code.google.com/p/robotframework/source/detail?r=62d08391b1be
Revision: 222743395354
Author: Pekka Klärck
Date: Sun Dec 18 16:32:16 2011
Log: Result writing: 1) Nuked builders and moved logging to
resultwriter. 2...
http://code.google.com/p/robotframework/source/detail?r=222743395354
==============================================================================
Revision: 62d08391b1be
Author: Pekka Klärck
Date: Sun Dec 18 14:26:45 2011
Log: StringCache: No need to keep count on an index when it is the
same as size of the cache. Verified using timeit that this doesn't accect
performance at all.
http://code.google.com/p/robotframework/source/detail?r=62d08391b1be
Modified:
/src/robot/reporting/stringcache.py
=======================================
--- /src/robot/reporting/stringcache.py Sun Dec 18 03:09:57 2011
+++ /src/robot/reporting/stringcache.py Sun Dec 18 14:26:45 2011
@@ -34,15 +34,13 @@
def __init__(self):
self._cache = {'*': self._zero_index}
- self._index = 1
def add(self, text):
if not text:
return self._zero_index
text = self._encode(text)
if text not in self._cache:
- self._cache[text] = StringIndex(self._index)
- self._index += 1
+ self._cache[text] = StringIndex(len(self._cache))
return self._cache[text]
def _encode(self, text):
==============================================================================
Revision: 222743395354
Author: Pekka Klärck
Date: Sun Dec 18 16:32:16 2011
Log: Result writing: 1) Nuked builders and moved logging to
resultwriter. 2) General cleanup. 3) Use -1 as RC (not DATA_ERROR i.e. 252)
when no outputs are created and raise exception if that happens with rebot
(that results to 252 RC in the end).
http://code.google.com/p/robotframework/source/detail?r=222743395354
Deleted:
/src/robot/reporting/builders.py
Modified:
/atest/robot/cli/rebot/status_rc.txt
/src/robot/__init__.py
/src/robot/reporting/resultwriter.py
/utest/reporting/test_reporting.py
=======================================
--- /src/robot/reporting/builders.py Sun Dec 18 02:58:17 2011
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright 2008-2011 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.
-
-from __future__ import with_statement
-
-
-from robot.errors import DataError
-from robot.output import LOGGER
-from robot.result.outputwriter import OutputWriter
-
-from .xunitwriter import XUnitWriter
-from .logreportwriters import LogWriter, ReportWriter
-
-
-class OutputBuilder(object):
-
- def __init__(self, model):
- self._model = model
-
- def build(self, path):
- try:
- writer = OutputWriter(path)
- except DataError, err:
- LOGGER.error(unicode(err))
- else:
- self._model.visit(writer)
- LOGGER.output_file('Output', path)
-
-
-class XUnitBuilder(object):
-
- def __init__(self, model):
- self._model = model
-
- def build(self, path):
- try:
- writer = XUnitWriter(path)
- except EnvironmentError, err:
- LOGGER.error("Opening XUnit result file '%s' failed: %s"
- % (path, err.strerror))
- else:
- self._model.visit(writer)
- LOGGER.output_file('XUnit', path)
-
-
-
-class LogBuilder(object):
-
- def __init__(self, js_model):
- self._js_model = js_model
-
- def build(self, path, config):
- try:
- LogWriter(self._js_model).write(path, config)
- except EnvironmentError, err:
- # Cannot use err.filename due to
http://bugs.jython.org/issue1825
- # and thus error has wrong file name if writing split log
fails.
- LOGGER.error("Writing log file '%s' failed: %s" % (path,
err.strerror))
- else:
- LOGGER.output_file('Log', path)
-
-
-
-class ReportBuilder(object):
-
- def __init__(self, js_model):
- self._js_model = js_model
-
- def build(self, path, config):
- try:
- ReportWriter(self._js_model).write(path, config)
- except EnvironmentError, err:
- LOGGER.error("Writing report file '%s' failed: %s" % (path,
err.strerror))
- else:
- LOGGER.output_file('Report', path)
=======================================
--- /atest/robot/cli/rebot/status_rc.txt Wed Nov 30 06:12:07 2011
+++ /atest/robot/cli/rebot/status_rc.txt Sun Dec 18 16:32:16 2011
@@ -12,6 +12,7 @@
${PASSING TESTS} ${MISCDIR}/normal.html
${FAILING TESTS} ${MISCDIR}/pass_and_fail.html
${REPORT} ${TEMPDIR}${/}robot-testing-report.html
+${NO OUTPUTS} [ ERROR ] No outputs created.\n\nTry --help for usage
information.
*** Test Cases ***
@@ -30,9 +31,9 @@
Zero RC when critical tests fail with --NoStatusRC
--nostatusrc ${FAILING} rc=0
-DATA_ERROR (252) when no output is created
- ${PASSING} rc=252 report=NONE
- --nostatusrc ${FAILING} rc=252 report=NONE
+Error when no output is created
+ ${PASSING} rc=252 output=${NO OUTPUTS}
report=NONE
+ --nostatusrc ${FAILING} rc=252 output=${NO OUTPUTS}
report=NONE
*** Keywords ***
@@ -47,7 +48,9 @@
Remove Files ${PASSING} ${FAILING}
Run Rebot and Verify RC
- [Arguments] ${options & source} ${rc}= ${report}=${REPORT}
- ${returned} ${output} = Run And Return RC And Output ${REBOT} --log
NONE --report ${report} ${options & source}
- Run Keyword If ${rc} != ${returned} Log ${output}
- Should Be Equal As Integers ${returned} ${rc}
+ [Arguments] ${options & source} ${rc}= ${output}=
${report}=${REPORT}
+ ${returned rc} ${returned output} = Run And Return RC And Output
+ ... ${REBOT} --log NONE --report ${report} ${options & source}
+ Run Keyword If ${rc} != ${returned rc} Log ${output}
+ Should Be Equal As Integers ${returned rc} ${rc}
+ Run Keyword If """${output}""" Should Be Equal ${returned output}
${output}
=======================================
--- /src/robot/__init__.py Fri Dec 2 03:27:16 2011
+++ /src/robot/__init__.py Sun Dec 18 16:32:16 2011
@@ -130,7 +130,7 @@
output.close(suite)
if settings.is_rebot_needed():
output, settings = settings.get_rebot_datasource_and_settings()
- ResultWriter(settings, output).write_results()
+ ResultWriter(output).write_results(settings)
LOGGER.close()
return suite.return_code
@@ -153,7 +153,9 @@
settings = RebotSettings(options)
LOGGER.register_console_logger(colors=settings['MonitorColors'])
LOGGER.disable_message_cache()
- rc = ResultWriter(settings, *datasources).write_results()
+ rc = ResultWriter(*datasources).write_results(settings)
+ if rc < 0:
+ raise DataError('No outputs created.')
LOGGER.close()
return rc
=======================================
--- /src/robot/reporting/resultwriter.py Wed Dec 14 00:37:51 2011
+++ /src/robot/reporting/resultwriter.py Sun Dec 18 16:32:16 2011
@@ -12,70 +12,97 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from robot.errors import DATA_ERROR
-from robot.reporting.jsmodelbuilders import JsModelBuilder
+from robot.errors import DataError
+from robot.output import LOGGER
from robot.result import ResultFromXml
-from .builders import LogBuilder, ReportBuilder, XUnitBuilder,
OutputBuilder
+# TODO: OutputWriter belongs into robot.reporting
+from robot.result.outputwriter import OutputWriter
+
+from .jsmodelbuilders import JsModelBuilder
+from .logreportwriters import LogWriter, ReportWriter
+from .xunitwriter import XUnitWriter
class ResultWriter(object):
- def __init__(self, settings, *data_sources):
- self._settings = settings
- self._result = Result(settings, data_sources)
-
- def write_results(self):
- settings = self._settings
- self._write_output(settings.output)
- self._write_xunit(settings.xunit)
- self._write_log(settings.log, settings.log_config)
- self._write_report(settings.report, settings.report_config)
- return self._result.return_code
-
- def _write_output(self, output):
- if output:
- OutputBuilder(self._result.model).build(output)
-
- def _write_xunit(self, xunit):
- if xunit:
- XUnitBuilder(self._result.model).build(xunit)
-
- def _write_log(self, log, config):
- if log:
- LogBuilder(self._result.js_model).build(log, config)
-
- def _write_report(self, report, config):
- if report:
- self._result.js_model.remove_data_not_needed_in_report()
- ReportBuilder(self._result.js_model).build(report, config)
+ def __init__(self, *data_sources):
+ self._data_sources = data_sources
+
+ def write_results(self, settings, results=None):
+ results = results or Results(self._data_sources, settings)
+ if settings.output:
+ self._write_output(results.result, settings.output)
+ if settings.xunit:
+ self._write_xunit(results.result, settings.xunit)
+ if settings.log:
+ self._write_log(results.js_result, settings.log,
settings.log_config)
+ if settings.report:
+ results.js_result.remove_data_not_needed_in_report()
+ self._write_report(results.js_result, settings.report,
settings.report_config)
+ return results.return_code
+
+ def _write_output(self, result, path):
+ try:
+ result.visit(OutputWriter(path))
+ except DataError, err:
+ LOGGER.error(unicode(err))
+ else:
+ LOGGER.output_file('Output', path)
+
+ def _write_xunit(self, result, path):
+ try:
+ result.visit(XUnitWriter(path))
+ except EnvironmentError, err:
+ LOGGER.error("Opening XUnit result file '%s' failed: %s"
+ % (path, err.strerror))
+ else:
+ LOGGER.output_file('XUnit', path)
+
+ def _write_log(self, js_result, path, config):
+ try:
+ LogWriter(js_result).write(path, config)
+ except EnvironmentError, err:
+ # Cannot use err.filename due to
http://bugs.jython.org/issue1825
+ # and thus error has wrong file name if writing split log
fails.
+ LOGGER.error("Writing log file '%s' failed: %s" % (path,
err.strerror))
+ else:
+ LOGGER.output_file('Log', path)
+
+ def _write_report(self, js_result, path, config):
+ try:
+ ReportWriter(js_result).write(path, config)
+ except EnvironmentError, err:
+ LOGGER.error("Writing report file '%s' failed: %s" % (path,
err.strerror))
+ else:
+ LOGGER.output_file('Report', path)
-class Result(object):
-
- def __init__(self, settings, data_sources):
- self._settings = settings
+class Results(object):
+
+ def __init__(self, data_sources, settings):
self._data_sources = data_sources
- self._model = None
- self._js_model = None
- self.return_code = DATA_ERROR
+ self._settings = settings
+ self._result = None
+ self._js_result = None
+ self.return_code = -1
@property
- def model(self):
- if self._model is None:
- self._model = ResultFromXml(*self._data_sources)
- self._model.configure(self._settings.status_rc,
- self._settings.suite_config,
- self._settings.statistics_config)
- self.return_code = self._model.return_code
- return self._model
+ def result(self):
+ if self._result is None:
+ self._result = ResultFromXml(*self._data_sources)
+ self._result.configure(self._settings.status_rc,
+ self._settings.suite_config,
+ self._settings.statistics_config)
+ self.return_code = self._result.return_code
+ return self._result
@property
- def js_model(self):
- if self._js_model is None:
+ def js_result(self):
+ if self._js_result is None:
builder = JsModelBuilder(log_path=self._settings.log,
split_log=self._settings.split_log,
prune_input_to_save_memory=True)
- self._js_model = builder.build_from(self.model)
- self._model = None
- return self._js_model
+ self._js_result = builder.build_from(self.result)
+ self._result = None
+ return self._js_result
=======================================
--- /utest/reporting/test_reporting.py Wed Dec 7 10:52:24 2011
+++ /utest/reporting/test_reporting.py Sun Dec 18 16:32:16 2011
@@ -1,173 +1,179 @@
from StringIO import StringIO
import os
import unittest
-from robot.reporting.resultwriter import ResultWriter, Result
+from robot.reporting.resultwriter import ResultWriter, Results
from robot.output import LOGGER
from robot.result.executionresult import ExecutionResult
+from robot.result.executionerrors import ExecutionErrors
from robot.result.testsuite import TestSuite
from robot.utils.asserts import assert_true, assert_equals
LOGGER.disable_automatic_console_logger()
-class TestReporting(unittest.TestCase):
-
+
+class TestReporting(unittest.TestCase):
EXPECTED_SUITE_NAME = 'My Suite Name'
EXPECTED_TEST_NAME = 'My Test Name'
EXPECTED_KEYWORD_NAME = 'My Keyword Name'
EXPECTED_FAILING_TEST = 'My Failing Test'
EXPECTED_DEBUG_MESSAGE = '1111DEBUG777'
-
- def setUp(self):
- self._settings = lambda:0
- self._settings.log = None
- self._settings.log_config = None
- self._settings.split_log = False
- self._settings.report = None
- self._settings.report_config = None
- self._settings.output = None
- self._settings.xunit = None
- self._settings.status_rc = True
- self._settings.suite_config = {}
- self._settings.statistics_config = {}
- self._create_suite_and_writer()
-
- def _create_suite_and_writer(self):
- self._root_suite = TestSuite(name=self.EXPECTED_SUITE_NAME)
- self._root_suite.tests.create(name=self.EXPECTED_TEST_NAME).\
- keywords.create(name=self.EXPECTED_KEYWORD_NAME,
- status='PASS')
- self._root_suite.tests.create(name=self.EXPECTED_FAILING_TEST).\
- keywords.create(name=self.EXPECTED_KEYWORD_NAME).\
-
messages.create(message=self.EXPECTED_DEBUG_MESSAGE,
- level='DEBUG',
- timestamp='20201212 12:12:12.000')
- self._writer = ResultWriter(self._settings)
- self._writer._result._model = ExecutionResult(self._root_suite)
-
- def test_generate_report_and_log(self):
- self._settings.log = ClosableOutput('log.html')
- self._settings.report = ClosableOutput('report.html')
- self._write_results()
- self._verify_log()
- self._verify_report()
-
- def _write_results(self):
- self._writer.write_results()
-
- def _verify_log(self):
- log = self._settings.log.getvalue()
- assert_true(self.EXPECTED_KEYWORD_NAME in log)
- assert_true(self.EXPECTED_SUITE_NAME in log)
- assert_true(self.EXPECTED_TEST_NAME in log)
- assert_true(self.EXPECTED_FAILING_TEST in log)
-
- def _verify_report(self):
- report = self._settings.report.getvalue()
- assert_true(self.EXPECTED_KEYWORD_NAME not in report)
- assert_true(self.EXPECTED_SUITE_NAME in report)
- assert_true(self.EXPECTED_TEST_NAME in report)
- assert_true(self.EXPECTED_FAILING_TEST in report)
-
- def test_no_generation(self):
- self._writer._result._model = None
- self._write_results()
- assert_equals(self._writer._result._model, None)
-
- def test_only_log(self):
- self._settings.log = ClosableOutput('log.html')
- self._write_results()
- self._verify_log()
-
- def test_only_report(self):
- self._settings.report = ClosableOutput('report.html')
- self._write_results()
- self._verify_report()
-
- def test_only_xunit(self):
- self._settings.xunit = ClosableOutput('xunit.xml')
- self._write_results()
- self._verify_xunit()
-
- def test_only_output_generation(self):
- self._settings.output = ClosableOutput('output.xml')
- self._write_results()
- self._verify_output()
-
- def test_generate_all(self):
- self._settings.log = ClosableOutput('l.html')
- self._settings.report = ClosableOutput('r.html')
- self._settings.xunit = ClosableOutput('x.xml')
- self._settings.output = ClosableOutput('o.xml')
- self._write_results()
- self._verify_log()
- self._verify_report()
- self._verify_xunit()
- self._verify_output()
-
- def test_log_generation_removes_keywords_from_original_model(self):
- self._settings.log = ClosableOutput('log.html')
- self._write_results()
- for test in self._root_suite.tests:
- assert_equals(len(test.keywords), 0)
-
- def _verify_xunit(self):
- xunit = self._settings.xunit.getvalue()
- assert_true(self.EXPECTED_DEBUG_MESSAGE in xunit)
-
- def _verify_output(self):
- assert_true(self._settings.output.getvalue())
-
-
-if os.name == 'java':
- import java.io.OutputStream
- import java.lang.String
-
- class ClosableOutput(java.io.OutputStream):
- def __init__(self, path):
- self._output = StringIO()
- self._path = path
-
- __enter__ = lambda *args: 0
- __exit__ = lambda self, *args: self.close()
-
- def write(self, *args):
- self._output.write(java.lang.String(args[0]))
-
- def close(self):
- self.value = self._output.getvalue()
- self._output.close()
-
- def getvalue(self):
- return self.value
-
- def __str__(self):
- return self._path
-
-else:
-
- class ClosableOutput(object):
-
- def __init__(self, path):
- self._output = StringIO()
- self._path = path
-
- __enter__= lambda *args: 0
- __exit__ = lambda self, *args: self.close()
-
- def write(self, data):
- self._output.write(data)
-
- def close(self):
- self.value = self._output.getvalue()
- self._output.close()
-
- def getvalue(self):
- return self.value
-
- def __str__(self):
- return self._path
+ EXPECTED_ERROR_MESSAGE = 'ERROR M355463'
+
+ def test_no_generation(self):
+ settings = StubSettings()
+ results = StubResults(None, settings)
+ rc = ResultWriter().write_results(settings, results)
+ assert_equals(rc, -1)
+
+ def test_only_output(self):
+ output = ClosableOutput('output.xml')
+ self._write_results(output=output)
+ self._verify_output(output.value)
+
+ def test_only_xunit(self):
+ xunit = ClosableOutput('xunit.xml')
+ self._write_results(xunit=xunit)
+ self._verify_xunit(xunit.value)
+
+ def test_only_log(self):
+ log = ClosableOutput('log.html')
+ self._write_results(log=log)
+ self._verify_log(log.value)
+
+ def test_only_report(self):
+ report = ClosableOutput('report.html')
+ self._write_results(report=report)
+ self._verify_report(report.value)
+
+ def test_log_and_report(self):
+ log = ClosableOutput('log.html')
+ report = ClosableOutput('report.html')
+ self._write_results(log=log, report=report)
+ self._verify_log(log.value)
+ self._verify_report(report.value)
+
+ def test_generate_all(self):
+ output = ClosableOutput('o.xml')
+ xunit = ClosableOutput('x.xml')
+ log = ClosableOutput('l.html')
+ report = ClosableOutput('r.html')
+ self._write_results(output=output, xunit=xunit, log=log,
report=report)
+ self._verify_output(output.value)
+ self._verify_xunit(xunit.value)
+ self._verify_log(log.value)
+ self._verify_report(report.value)
+
+ def test_log_generation_removes_keywords_from_execution_result(self):
+ self._write_results(log=ClosableOutput('log.html'))
+ for test in self.execution_result.suite.tests:
+ assert_equals(len(test.keywords), 0)
+
+ def _write_results(self, **settings):
+ self.execution_result = self._get_execution_result()
+ settings = StubSettings(**settings)
+ results = StubResults(self.execution_result, settings)
+ rc = ResultWriter().write_results(settings, results)
+ assert_equals(rc, 1)
+
+ def _get_execution_result(self):
+ suite = TestSuite(name=self.EXPECTED_SUITE_NAME)
+ tc = suite.tests.create(name=self.EXPECTED_TEST_NAME,
status='PASS')
+ tc.keywords.create(name=self.EXPECTED_KEYWORD_NAME, status='PASS')
+ tc = suite.tests.create(name=self.EXPECTED_FAILING_TEST)
+ kw = tc.keywords.create(name=self.EXPECTED_KEYWORD_NAME)
+ kw.messages.create(message=self.EXPECTED_DEBUG_MESSAGE,
+ level='DEBUG', timestamp='20201212
12:12:12.000')
+ errors = ExecutionErrors()
+ errors.messages.create(message=self.EXPECTED_ERROR_MESSAGE,
+ level='ERROR', timestamp='20201212
12:12:12.000')
+ return ExecutionResult(suite, errors)
+
+ def _verify_output(self, content):
+ assert_true(self.EXPECTED_SUITE_NAME in content)
+ assert_true(self.EXPECTED_TEST_NAME in content)
+ assert_true(self.EXPECTED_FAILING_TEST in content)
+ assert_true(self.EXPECTED_KEYWORD_NAME in content)
+ assert_true(self.EXPECTED_DEBUG_MESSAGE in content)
+ assert_true(self.EXPECTED_ERROR_MESSAGE in content)
+
+ def _verify_xunit(self, content):
+ assert_true(self.EXPECTED_SUITE_NAME in content)
+ assert_true(self.EXPECTED_TEST_NAME in content)
+ assert_true(self.EXPECTED_FAILING_TEST in content)
+ assert_true(self.EXPECTED_KEYWORD_NAME not in content)
+ assert_true(self.EXPECTED_DEBUG_MESSAGE in content)
+ assert_true(self.EXPECTED_ERROR_MESSAGE not in content)
+
+ def _verify_log(self, content):
+ self._verify_output(content)
+
+ def _verify_report(self, content):
+ assert_true(self.EXPECTED_SUITE_NAME in content)
+ assert_true(self.EXPECTED_TEST_NAME in content)
+ assert_true(self.EXPECTED_FAILING_TEST in content)
+ assert_true(self.EXPECTED_KEYWORD_NAME not in content)
+ assert_true(self.EXPECTED_DEBUG_MESSAGE not in content)
+ assert_true(self.EXPECTED_ERROR_MESSAGE not in content)
+
+
+class StubSettings(object):
+ log = None
+ log_config = None
+ split_log = False
+ report = None
+ report_config = None
+ output = None
+ xunit = None
+ status_rc = True
+ suite_config = {}
+ statistics_config = {}
+
+ def __init__(self, **settings):
+ self.__dict__.update(settings)
+
+
+class StubResults(Results):
+
+ def __init__(self, result, settings):
+ Results.__init__(self, None, settings)
+ self._result = result
+ if result:
+ self.return_code = result.return_code
+
+
+class ClosableOutput(object):
+
+ def __init__(self, path):
+ self._output = StringIO()
+ self._path = path
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def write(self, data):
+ self._output.write(data)
+
+ def close(self):
+ self.value = self._output.getvalue()
+ self._output.close()
+
+ def __str__(self):
+ return self._path
+
+
+if os.name == 'java':
+ from java.io import OutputStream
+ from java.lang import String
+
+ class ClosableOutput(ClosableOutput, OutputStream):
+
+ def write(self, *args):
+ self._output.write(String(args[0]))
if __name__ == '__main__':