3 new revisions:
Revision: bffc2eb3baaf
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 05:53:07 2011
Log: settings: propertys for some settings. more can be added later.
http://code.google.com/p/robotframework/source/detail?r=bffc2eb3baaf
Revision: a897cc6dea43
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 06:09:02 2011
Log: cleanup
http://code.google.com/p/robotframework/source/detail?r=a897cc6dea43
Revision: e3b8c021ba79
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 06:12:07 2011
Log: Refactored result writing
http://code.google.com/p/robotframework/source/detail?r=e3b8c021ba79
==============================================================================
Revision: bffc2eb3baaf
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 05:53:07 2011
Log: settings: propertys for some settings. more can be added later.
http://code.google.com/p/robotframework/source/detail?r=bffc2eb3baaf
Modified:
/src/robot/conf/settings.py
=======================================
--- /src/robot/conf/settings.py Wed Nov 30 03:11:56 2011
+++ /src/robot/conf/settings.py Wed Nov 30 05:53:07 2011
@@ -232,6 +232,34 @@
return '\n'.join('%s: %s' % (name, self._opts[name])
for name in sorted(self._opts))
+ @property
+ def output(self):
+ return self._get_file('Output')
+
+ @property
+ def log(self):
+ return self._get_file('Log')
+
+ @property
+ def report(self):
+ return self._get_file('Report')
+
+ @property
+ def xunit(self):
+ return self._get_file('XUnitFile')
+
+ def _get_file(self, name):
+ value = self[name]
+ return value if value != 'NONE' else None
+
+ @property
+ def split_log(self):
+ return self['SplitLog']
+
+ @property
+ def status_rc(self):
+ return not self['NoStatusRC']
+
class RobotSettings(_BaseSettings):
_extra_cli_opts = {'Output' : ('output', 'output.xml'),
==============================================================================
Revision: a897cc6dea43
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 06:09:02 2011
Log: cleanup
http://code.google.com/p/robotframework/source/detail?r=a897cc6dea43
Modified:
/src/robot/reporting/jsondatamodel.py
=======================================
--- /src/robot/reporting/jsondatamodel.py Mon Oct 24 03:12:31 2011
+++ /src/robot/reporting/jsondatamodel.py Wed Nov 30 06:09:02 2011
@@ -20,7 +20,6 @@
class DataModelWriter(object):
-
_OUTPUT = 'window.output'
_SETTINGS = 'window.settings'
_SUITE_KEY = 'suite'
@@ -129,14 +128,14 @@
class SeparatingWriter(object):
- def __init__(self, output, separator):
+ def __init__(self, output, separator=''):
self._dumper = JsonDumper(output)
self._separator = separator
def separator(self):
self._dumper.write(self._separator)
- def dump_json(self, prefix, data, postfix = ';\n', mapping=None):
+ def dump_json(self, prefix, data, postfix=';\n', mapping=None):
if prefix:
self.write(prefix)
self._dumper.dump(data, mapping)
@@ -161,7 +160,7 @@
def link(self, name):
key = object()
- return _SubResult(key, 1, {key:name})
+ return _SubResult(key, 1, {key: name})
class SplittingSuiteWriter(object):
@@ -189,7 +188,8 @@
return 'window.sPart%s' % self._index
def _dump_suite_part(self, result):
- self._writer.dump_json(self._list_name()+' = ', result.data_block,
mapping=result.mapping)
+ self._writer.dump_json(self._list_name()+' = ', result.data_block,
+ mapping=result.mapping)
self._writer.separator()
new_result = result.link(self._list_name())
self._index += 1
==============================================================================
Revision: e3b8c021ba79
Author: Robot Framework Developers ([email protected])
Date: Wed Nov 30 06:12:07 2011
Log: Refactored result writing
http://code.google.com/p/robotframework/source/detail?r=e3b8c021ba79
Modified:
/atest/robot/cli/rebot/status_rc.txt
/src/robot/__init__.py
/src/robot/reporting/__init__.py
/src/robot/reporting/builders.py
/src/robot/reporting/parsingcontext.py
/src/robot/reporting/resultwriter.py
=======================================
--- /atest/robot/cli/rebot/status_rc.txt Mon Jun 13 05:38:29 2011
+++ /atest/robot/cli/rebot/status_rc.txt Wed Nov 30 06:12:07 2011
@@ -1,7 +1,8 @@
*** Settings ***
Suite Setup Set Runners and generate input files
Suite Teardown Remove input files
-Default Tags regression pybot jybot
+Test Template Run Rebot and Verify RC
+Force Tags regression pybot jybot
Resource rebot_cli_resource.txt
*** Variables ***
@@ -10,23 +11,28 @@
${MISCDIR} ${CURDIR}/../../../testdata/misc
${PASSING TESTS} ${MISCDIR}/normal.html
${FAILING TESTS} ${MISCDIR}/pass_and_fail.html
+${REPORT} ${TEMPDIR}${/}robot-testing-report.html
*** Test Cases ***
Zero RC when all tests pass
- Run Rebot and Verify RC ${PASSING} rc=0
+ ${PASSING} rc=0
Zero RC when all critical tests pass
- Run Rebot and Verify RC --critical pass ${FAILING} rc=0
+ --critical pass ${FAILING} rc=0
Non-zero RC when critical tests fail
- Run Rebot and Verify RC ${FAILING} rc=1
+ ${FAILING} rc=1
Zero RC when all tests pass with --NoStatusRC
- Run Rebot and Verify RC --NoStatusRC ${PASSING} rc=0
+ --NoStatusRC ${PASSING} rc=0
Zero RC when critical tests fail with --NoStatusRC
- Run Rebot and Verify RC --nostatusrc ${FAILING} rc=0
+ --nostatusrc ${FAILING} rc=0
+
+DATA_ERROR (252) when no output is created
+ ${PASSING} rc=252 report=NONE
+ --nostatusrc ${FAILING} rc=252 report=NONE
*** Keywords ***
@@ -41,6 +47,7 @@
Remove Files ${PASSING} ${FAILING}
Run Rebot and Verify RC
- [Arguments] ${options & source} ${rc}=
- ${returned}= Run And Return Rc ${REBOT} --log NONE --report NONE
${options & source}
+ [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}
=======================================
--- /src/robot/__init__.py Wed Nov 30 05:26:02 2011
+++ /src/robot/__init__.py Wed Nov 30 06:12:07 2011
@@ -46,7 +46,7 @@
from output import Output, LOGGER, pyloggingconf
from conf import RobotSettings, RebotSettings
from running import TestSuite, STOP_SIGNAL_MONITOR
-from robot.reporting import RobotResultWriter, RebotResultWriter
+from robot.reporting import ResultWriter
from errors import (DataError, Information, INFO_PRINTED, DATA_ERROR,
STOPPED_BY_USER, FRAMEWORK_ERROR)
from variables import init_global_variables
@@ -130,7 +130,7 @@
output.close(suite)
if settings.is_rebot_needed():
output, settings = settings.get_rebot_datasource_and_settings()
- RobotResultWriter(settings).write_results(output)
+ ResultWriter(settings).write_results(output)
LOGGER.close()
return suite.return_code
@@ -153,7 +153,7 @@
settings = RebotSettings(options)
LOGGER.register_console_logger(colors=settings['MonitorColors'])
LOGGER.disable_message_cache()
- rc = RebotResultWriter(settings).write_results(*datasources)
+ rc = ResultWriter(settings).write_results(*datasources)
LOGGER.close()
return rc
=======================================
--- /src/robot/reporting/__init__.py Wed Nov 16 00:35:41 2011
+++ /src/robot/reporting/__init__.py Wed Nov 30 06:12:07 2011
@@ -13,4 +13,4 @@
# limitations under the License.
-from resultwriter import RobotResultWriter, RebotResultWriter
+from resultwriter import ResultWriter
=======================================
--- /src/robot/reporting/builders.py Wed Nov 30 05:13:54 2011
+++ /src/robot/reporting/builders.py Wed Nov 30 06:12:07 2011
@@ -39,45 +39,27 @@
class _Builder(object):
- def __init__(self, context):
- self._settings = context.settings
- self._context = context
- self._path = self._parse_file(self._type)
-
- def build(self):
- if self._path:
- self._build()
-
- def _build(self):
+ def __init__(self, model):
+ self._model = model
+
+ def build(self, path):
raise NotImplementedError(self.__class__.__name__)
- def _parse_file(self, name):
- value = self._settings[name]
- return value if value != 'NONE' else None
-
class OutputBuilder(_Builder):
- _type = 'Output'
-
- def _build(self):
- path = self._path
- if path == 'NONE':
- return
+
+ def build(self, path):
writer = RebotXMLWriter(path)
- self._context.result_from_xml.visit(writer)
+ self._model.visit(writer)
LOGGER.output_file('Output', path)
class XUnitBuilder(_Builder):
- _type = 'XUnitFile'
-
- def _build(self):
- path = self._path
- if path == 'NONE':
- return
+
+ def build(self, path):
writer = XUnitWriter(path) # TODO: handle (with atests) error in
opening output file
try:
- self._context.result_from_xml.visit(writer)
+ self._model.visit(writer)
except:
raise DataError("Writing XUnit result file '%s' failed: %s" %
(path, utils.get_error_message()))
@@ -87,25 +69,12 @@
class _HTMLFileBuilder(_Builder):
- _type = NotImplemented
- _template = NotImplemented
-
- def _build(self):
- self._context.data_model.set_settings(self._get_settings())
- self._format_data()
- if self._write_file():
- LOGGER.output_file(self._type, self._path)
-
- def _url_from_path(self, source, destination):
- if not destination:
- return None
- return utils.get_link_path(destination, os.path.dirname(source))
-
- def _write_file(self):
+
+ def _write_file(self, path, template):
try:
- with codecs.open(self._path, 'w', encoding='UTF-8') as outfile:
- writer = HTMLFileWriter(outfile, self._context.data_model)
- for line in _WebContentFile(self._template):
+ with codecs.open(path, 'w', encoding='UTF-8') as outfile:
+ writer = HTMLFileWriter(outfile, self._model)
+ for line in _WebContentFile(template):
writer.line(line)
except EnvironmentError, err:
LOGGER.error("Opening '%s' failed: %s"
@@ -115,55 +84,32 @@
class LogBuilder(_HTMLFileBuilder):
- _type = 'Log'
- _template = 'log.html'
-
- def _format_data(self):
- if self._context.data_model._split_results:
- self._write_split_tests()
-
- def _write_split_tests(self):
- basename = os.path.splitext(self._path)[0]
- for index, (keywords, strings) in
enumerate(self._context.data_model._split_results):
+
+ def build(self, path):
+ if self._model._split_results:
+ self._write_split_tests(path)
+ if self._write_file(path, 'log.html'):
+ LOGGER.output_file('Log', path)
+
+ def _write_split_tests(self, path):
+ basename = os.path.splitext(path)[0]
+ for index, (keywords, strings) in
enumerate(self._model._split_results):
index += 1 # enumerate accepts start index only in Py 2.6+
self._write_test(index, keywords, strings, '%s-%d.js' %
(basename, index))
def _write_test(self, index, keywords, strings, path):
- # TODO: Refactor heavily - ask Jussi or Peke for more details
with codecs.open(path, 'w', encoding='UTF-8') as outfile:
writer = SeparatingWriter(outfile, '')
writer.dump_json('window.keywords%d = ' % index, keywords)
writer.dump_json('window.strings%d = ' % index, strings)
writer.write('window.fileLoading.notify("%s");\n' %
os.path.basename(path))
- def _get_settings(self):
- return {
- 'title': self._settings['LogTitle'],
- 'reportURL': self._url_from_path(self._path,
- self._parse_file('Report')),
- 'splitLogBase':
os.path.basename(os.path.splitext(self._path)[0])
- }
-
class ReportBuilder(_HTMLFileBuilder):
- _type = 'Report'
- _template = 'report.html'
-
- def _format_data(self):
- self._context.data_model.remove_errors()
- self._context.data_model.remove_keywords()
-
- def _get_settings(self):
- return {
- 'title': self._settings['ReportTitle'],
- 'background' : self._resolve_background_colors(),
- 'logURL': self._url_from_path(self._path,
- self._parse_file('Log'))
- }
-
- def _resolve_background_colors(self):
- colors = self._settings['ReportBackground']
- return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail':
colors[2]}
+
+ def build(self, path):
+ if self._write_file(path, 'report.html'):
+ LOGGER.output_file('Report', path)
class HTMLFileWriter(object):
=======================================
--- /src/robot/reporting/parsingcontext.py Tue Nov 29 01:53:28 2011
+++ /src/robot/reporting/parsingcontext.py Wed Nov 30 06:12:07 2011
@@ -20,7 +20,7 @@
class Context(object):
- def __init__(self, log_path='NONE', split_log=False):
+ def __init__(self, log_path=None, split_log=False):
self._main_text_cache = TextCache()
self._current_texts = self._main_text_cache
self._split_text_caches = []
@@ -32,7 +32,7 @@
self._log_path = log_path
def get_rel_log_path(self, path):
- if path and os.path.exists(path) and self._log_path != 'NONE':
+ if path and os.path.exists(path) and self._log_path:
return utils.get_link_path(path,
os.path.dirname(self._log_path))
return ''
=======================================
--- /src/robot/reporting/resultwriter.py Wed Nov 30 05:26:02 2011
+++ /src/robot/reporting/resultwriter.py Wed Nov 30 06:12:07 2011
@@ -12,57 +12,93 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from robot.reporting.jsondatamodel import DataModelWriter
+import os
+
+from robot.errors import DATA_ERROR
from robot.result.builders import ResultFromXML
from robot.result.combiningvisitor import CombiningVisitor,
KeywordRemovingVisitor
from robot.result.datamodel import JSModelCreator
-
-from robot.reporting.builders import LogBuilder, ReportBuilder,
XUnitBuilder, OutputBuilder
+from robot import utils
+
+from .builders import LogBuilder, ReportBuilder, XUnitBuilder,
OutputBuilder
+from .jsondatamodel import DataModelWriter
-class _ResultWriter(object):
+class ResultWriter(object):
def __init__(self, settings):
- self.settings = settings
- self._xml_result = None
- self._data_model = None
- self._data_sources = []
+ self._settings = settings
+
+ def write_results(self, *data_sources):
+ settings = self._settings
+ result = Result(settings, data_sources)
+ if settings.output:
+ OutputBuilder(result.model).build(settings.output)
+ if settings.xunit:
+ XUnitBuilder(result.model).build(settings.xunit)
+ if settings.log:
+ LogBuilder(result.log_model).build(settings.log)
+ if settings.report:
+ ReportBuilder(result.report_model).build(settings.report)
+ return result.return_code
+
+
+class Result(object):
+
+ def __init__(self, settings, data_sources):
+ self._settings = settings
+ self._data_sources = data_sources
+ self._model = None
+ self._js_model = None
@property
- def data_model(self):
- if self._data_model is None:
- creator = JSModelCreator(log_path=self.settings['Log'],
- split_log=self.settings['SplitLog'])
- self.result_from_xml.visit(CombiningVisitor(creator,
KeywordRemovingVisitor()))
- self._data_model = DataModelWriter(creator.datamodel,
creator.split_results)
- return self._data_model
+ def return_code(self):
+ return self._model.return_code if self._model else DATA_ERROR
@property
- def result_from_xml(self):
- if self._xml_result is None:
- self._xml_result = ResultFromXML(*self._data_sources)
+ def model(self):
+ if self._model is None:
+ self._model = ResultFromXML(*self._data_sources)
# TODO: configure and configure_statistics really should be
combined somehow
-
self._xml_result.configure_statistics(*self.settings.statistics_configuration())
- self._xml_result.configure(status_rc=not
self.settings['NoStatusRC'],
-
**self.settings.result_configuration())
- return self._xml_result
-
-
-class RobotResultWriter(_ResultWriter):
-
- def write_results(self, data_source):
- self._data_sources = [data_source]
- XUnitBuilder(self).build()
- LogBuilder(self).build()
- ReportBuilder(self).build()
-
-
-class RebotResultWriter(_ResultWriter):
-
- def write_results(self, *data_sources):
- self._data_sources = data_sources
- OutputBuilder(self).build()
- XUnitBuilder(self).build()
- LogBuilder(self).build()
- ReportBuilder(self).build()
- return self.result_from_xml.return_code
+
self._model.configure_statistics(*self._settings.statistics_configuration())
+ self._model.configure(status_rc=self._settings.status_rc,
+ **self._settings.result_configuration())
+ return self._model
+
+ @property
+ def js_model(self):
+ if self._js_model is None:
+ creator = JSModelCreator(log_path=self._settings.log,
+ split_log=self._settings.split_log)
+ self.model.visit(CombiningVisitor(creator,
KeywordRemovingVisitor()))
+ self._js_model = DataModelWriter(creator.datamodel,
creator.split_results)
+ return self._js_model
+
+ @property
+ def log_model(self):
+ self.js_model.set_settings({
+ 'title': self._settings['LogTitle'],
+ 'reportURL': self._url_from_path(self._settings.log,
self._settings.report),
+ 'splitLogBase':
os.path.basename(os.path.splitext(self._settings.log)[0])
+ })
+ return self.js_model
+
+ @property
+ def report_model(self):
+ self.js_model.set_settings({
+ 'title': self._settings['ReportTitle'],
+ 'logURL': self._url_from_path(self._settings.report,
self._settings.log),
+ 'background' : self._resolve_background_colors(),
+ })
+ self.js_model.remove_errors()
+ self.js_model.remove_keywords()
+ return self.js_model
+
+ def _url_from_path(self, source, destination):
+ if not destination:
+ return None
+ return utils.get_link_path(destination, os.path.dirname(source))
+
+ def _resolve_background_colors(self):
+ colors = self._settings['ReportBackground']
+ return {'pass': colors[0], 'nonCriticalFail': colors[1], 'fail':
colors[2]}