Commit dff34472 authored by Jérome Perrin's avatar Jérome Perrin

Python coverage

Depends on slapos!1290

See merge request !1695
parents 455c5322 1c1618a3
......@@ -104,6 +104,9 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEqual(test_web.getPortalType(), 'Business Template')
self.assertEqual(test_web.getTitle(), 'test_web')
self.assertEqual(len(test_web.getRevision()), 28)
self.assertEqual(
test_web.getPublicationUrl(),
'http://www.erp5.org/dists/snapshot/test_bt5/test_web.bt5')
def _svn_setup_ssl(self):
"""
......@@ -139,6 +142,8 @@ class TestTemplateTool(ERP5TypeTestCase):
self.assertEqual(test_web.getPortalType(), 'Business Template')
self.assertEqual(test_web.getTitle(), 'test_web')
self.assertEqual(len(test_web.getRevision()), 28)
self.assertEqual(
test_web.getPublicationUrl(), bt5_url)
def test_00_updateBusinessTemplateFromUrl_simple(self):
"""
......@@ -549,6 +554,7 @@ class TestTemplateTool(ERP5TypeTestCase):
bt = self.templates_tool.getInstalledBusinessTemplate(bt5_name, strict=True)
self.assertNotEquals(bt, None)
self.assertEqual(bt.getTitle(), bt5_name)
self.assertEqual(bt.getPublicationUrl(), self._getBTPathAndIdList([bt5_name])[0][0])
# Repeat operation, the bt5 should be ignored
self.templates_tool.installBusinessTemplateListFromRepository([bt5_name])
......
......@@ -77,17 +77,18 @@ from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from OFS.Traversable import NotFound
from OFS import SimpleItem
from OFS.Image import Pdata
import coverage
from io import BytesIO
from copy import deepcopy
from zExceptions import BadRequest
from Products.ERP5Type.XMLExportImport import exportXML, customImporters
from Products.ERP5Type.Workflow import WorkflowHistoryList
from zLOG import LOG, WARNING, INFO
from zLOG import LOG, WARNING, INFO, PROBLEM
from warnings import warn
from lxml.etree import parse
from xml.sax.saxutils import escape
from Products.CMFCore.Expression import Expression
from six.moves.urllib.parse import quote, unquote
from six.moves.urllib.parse import quote, unquote, urlparse
from difflib import unified_diff
import posixpath
import transaction
......@@ -97,6 +98,7 @@ import threading
from ZODB.broken import Broken, BrokenModified
from Products.ERP5.genbt5list import BusinessTemplateRevision, \
item_name_list, item_set
from Products.ERP5Type.mixin.component import ComponentMixin
CACHE_DATABASE_PATH = None
try:
......@@ -1156,22 +1158,33 @@ class ObjectTemplateItem(BaseTemplateItem):
"""
pass
def onNewObject(self, obj):
def onNewObject(self, obj, context):
"""
Installation hook.
Called when installation process determined that object to install is
new on current site (it's not replacing an existing object).
`obj` parameter is the newly created object in its acquisition context.
`context` is the business template instance, in its acquisition context.
Can be overridden by subclasses.
"""
pass
if isinstance(obj, (PythonScript, ComponentMixin)) and coverage.Coverage.current():
relative_path = '/'.join(obj.getPhysicalPath()[len(context.getPortalObject().getPhysicalPath()):])
filename = os.path.join(
context.getPublicationUrl(),
self.__class__.__name__,
relative_path + '.py')
if os.path.exists(filename):
obj._erp5_coverage_filename = filename
else:
LOG('BusinessTemplate', PROBLEM, 'Could not find file for %s' % filename)
def onReplaceObject(self, obj):
def onReplaceObject(self, obj, context):
"""
Installation hook.
Called when installation process determined that object to install is
to replace an existing object on current site (it's not new).
`obj` parameter is the replaced object in its acquisition context.
`context` is the business template instance, in its acquisition context.
Can be overridden by subclasses.
"""
pass
......@@ -1416,9 +1429,9 @@ class ObjectTemplateItem(BaseTemplateItem):
if not object_existed:
# A new object was added, call the hook
self.onNewObject(obj)
self.onNewObject(obj, context)
else:
self.onReplaceObject(obj)
self.onReplaceObject(obj, context)
# mark a business template installation so in 'PortalType_afterClone' scripts
# we can implement logical for reseting or not attributes (i.e reference).
......@@ -1972,9 +1985,11 @@ class CategoryTemplateItem(ObjectTemplateItem):
def beforeInstall(self):
self._installed_new_category = False
return super(CategoryTemplateItem, self).beforeInstall()
def onNewObject(self, obj):
def onNewObject(self, obj, context):
self._installed_new_category = True
return super(CategoryTemplateItem, self).onNewObject(obj, context)
def afterInstall(self):
if self._installed_new_category:
......@@ -2392,7 +2407,8 @@ class WorkflowTemplateItem(ObjectTemplateItem):
continue
raise
container_ids = container.objectIds()
if object_id in container_ids: # Object already exists
object_existed = object_id in container_ids
if object_existed:
self._backupObject(action, trashbin, container_path, object_id, keep_subobjects=1)
container.manage_delObjects([object_id])
obj = self._objects[path]
......@@ -2402,6 +2418,11 @@ class WorkflowTemplateItem(ObjectTemplateItem):
obj = container._getOb(object_id)
obj.manage_afterClone(obj)
obj.wl_clearLocks()
if not object_existed:
# A new object was added, call the hook
self.onNewObject(obj, context)
else:
self.onReplaceObject(obj, context)
def uninstall(self, context, **kw):
object_path = kw.get('object_path', None)
......@@ -4218,7 +4239,7 @@ class _ZodbComponentTemplateItem(ObjectTemplateItem):
raise NotImplementedError
def __init__(self, id_list, tool_id='portal_components', **kw):
ObjectTemplateItem.__init__(self, id_list, tool_id=tool_id, **kw)
super(_ZodbComponentTemplateItem, self).__init__(id_list, tool_id=tool_id, **kw)
def isKeepWorkflowObjectLastHistoryOnly(self, path):
"""
......@@ -4248,9 +4269,13 @@ class _ZodbComponentTemplateItem(ObjectTemplateItem):
obj.workflow_history[wf_id] = WorkflowHistoryList([wf_history])
def onNewObject(self, _):
def onNewObject(self, obj, context):
self._do_reset = True
onReplaceObject = onNewObject
return super(_ZodbComponentTemplateItem, self).onNewObject(obj, context)
def onReplaceObject(self, obj, context):
self._do_reset = True
return super(_ZodbComponentTemplateItem, self).onReplaceObject(obj, context)
def afterInstall(self):
"""
......@@ -5718,6 +5743,9 @@ Business Template is a set of definitions, such as skins, portal types and categ
value = self.getProperty(id)
if not value:
continue
if id == 'publication_url':
if urlparse(value).scheme in ('file', ''):
continue
if prop_type in ('text', 'string', 'int', 'boolean'):
bta.addObject(str(value), name=id, path='bt', ext='')
elif prop_type in ('lines', 'tokens'):
......
......@@ -401,6 +401,7 @@ class TemplateTool (BaseTool):
bt = self._download_local(path, id)
bt.build(no_action=True)
bt.setPublicationUrl(url)
return bt
security.declareProtected('Import/Export objects', 'importBase64EncodedText')
......
......@@ -36,6 +36,7 @@ import imp
import collections
from six import reraise
import coverage
from Products.ERP5Type.Utils import ensure_list
from Products.ERP5.ERP5Site import getSite
from Products.ERP5Type import product_path as ERP5Type_product_path
......@@ -333,6 +334,14 @@ class ComponentDynamicPackage(ModuleType):
# This must be set for imports at least (see PEP 302)
module.__file__ = '<' + relative_url + '>'
if coverage.Coverage.current():
if hasattr(component, '_erp5_coverage_filename'):
module.__file__ = component._erp5_coverage_filename
else:
LOG(
"ERP5Type.Tool.ComponentTool",
WARNING,
"No coverage filesystem mapping for %s" % (module_fullname_alias or module_fullname))
# Only useful for get_source(), do it before exec'ing the source code
# so that the source code is properly display in case of error
......
......@@ -140,6 +140,9 @@ def main():
args.test_node_title, suite.allow_restart, test_suite_title,
args.project_title)
if test_result is not None:
os.environ['ERP5_TEST_RESULT_REVISION'] = test_result.revision
os.environ['ERP5_TEST_RESULT_ID'] = test_result.test_result_path.split('/')[-1]
assert revision == test_result.revision, (revision, test_result.revision)
while suite.acquire():
test = test_result.start(suite.running.keys())
......
......@@ -12,10 +12,7 @@ import errno
import random
import transaction
from glob import glob
try:
from coverage import coverage
except ImportError:
coverage = None
WIN = os.name == 'nt'
......@@ -27,8 +24,6 @@ Options:
-v, --verbose produce verbose output
-h, --help this help screen
-p, --profile print profiling results at the end
--coverage=STRING Use the given path as a coverage config file and
thus enable code coverateg report
--portal_id=STRING force id of the portal. Useful when using
--data_fs_path to run tests on an existing
Data.fs
......@@ -638,11 +633,6 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
signal.signal(signal.SIGINT, shutdown)
signal.signal(signal.SIGHUP, shutdown)
coverage_config = os.environ.get('coverage', None)
if coverage_config:
coverage_process = coverage(config_file=coverage_config)
coverage_process.start()
try:
save = int(os.environ.get('erp5_save_data_fs', 0))
load = int(os.environ.get('erp5_load_data_fs', 0))
......@@ -717,11 +707,6 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
# disconnected from it.
wcfs_server.stop()
if coverage_config:
coverage_process.stop()
coverage_process.save()
coverage_process.html_report()
if save and save_mysql:
save_mysql(verbosity)
......@@ -747,7 +732,7 @@ def main(argument_list=None):
sys.argv.extend(old_argv[1:])
try:
opts, args = getopt.getopt(sys.argv[1:],
"hpvD", ["help", "verbose", "profile", "coverage=", "portal_id=",
"hpvD", ["help", "verbose", "profile", "portal_id=",
"data_fs_path=",
"bt5_path=",
"firefox_bin=",
......@@ -810,11 +795,6 @@ def main(argument_list=None):
elif opt == '-D':
debug = 1
os.environ["erp5_debug_mode"] = str(debug)
elif opt == "--coverage":
if coverage:
os.environ['coverage'] = arg
else:
_print("WARNING Coverage module not found")
elif opt in ("-p", "--profile"):
os.environ['PROFILE_TESTS'] = "1"
# profiling of setup and teardown is disabled by default, just set
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment