Commit b3acec03 authored by Julien Muchembled's avatar Julien Muchembled

Unit tests: allow to download built BT from a running ERP5 instance

--bt5_path cmdline option now allows to specify the URL of a running template
tool. For example:

  $ runUnitTest.py --bt5_path='http://zope:zope@localhost:9001/erp5/portal_templates',/fallback_fs_path/bt5 testBug

This will try to download non-deleted built business templates, with the highest revision number.

--bt5_path is also changed to apply to core BT during creation of the site.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@33393 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 28649365
...@@ -1279,6 +1279,14 @@ def getBootstrapDirectory(): ...@@ -1279,6 +1279,14 @@ def getBootstrapDirectory():
product_path = package_home(globals()) product_path = package_home(globals())
return os.path.join(product_path, 'bootstrap') return os.path.join(product_path, 'bootstrap')
def getBootstrapBusinessTemplateUrl(bt_title):
"""
Return the path to download the given bootstrap business template
"""
path = os.path.join(getBootstrapDirectory(), bt_title)
if not os.path.exists(path):
path += '.bt5'
return path
# This PortalGenerator class was copied wholesale from CMF 1.5 which is # This PortalGenerator class was copied wholesale from CMF 1.5 which is
# identical to the one on 1.6, and hasn't been used by CMF itself since even # identical to the one on 1.6, and hasn't been used by CMF itself since even
...@@ -1443,9 +1451,6 @@ class ERP5Generator(PortalGenerator): ...@@ -1443,9 +1451,6 @@ class ERP5Generator(PortalGenerator):
klass = ERP5Site klass = ERP5Site
def getBootstrapDirectory(self):
return getBootstrapDirectory()
def create(self, def create(self,
parent, parent,
id, id,
...@@ -1806,7 +1811,7 @@ class ERP5Generator(PortalGenerator): ...@@ -1806,7 +1811,7 @@ class ERP5Generator(PortalGenerator):
'business_template_installation_workflow'): 'business_template_installation_workflow'):
if wf_id in tool.objectIds(): if wf_id in tool.objectIds():
tool.manage_delObjects([wf_id]) tool.manage_delObjects([wf_id])
bootstrap_dir = self.getBootstrapDirectory() bootstrap_dir = getBootstrapDirectory()
business_template_building_workflow = os.path.join( business_template_building_workflow = os.path.join(
bootstrap_dir, bootstrap_dir,
'business_template_building_workflow.xml') 'business_template_building_workflow.xml')
...@@ -1984,14 +1989,9 @@ class ERP5Generator(PortalGenerator): ...@@ -1984,14 +1989,9 @@ class ERP5Generator(PortalGenerator):
if template_tool is None: if template_tool is None:
return return
if template_tool.getInstalledBusinessTemplate('erp5_core') is None: if template_tool.getInstalledBusinessTemplate('erp5_core') is None:
bootstrap_dir = self.getBootstrapDirectory()
for bt in ('erp5_core', p.erp5_catalog_storage, 'erp5_xhtml_style'): for bt in ('erp5_core', p.erp5_catalog_storage, 'erp5_xhtml_style'):
if not bt: if not bt:
continue continue
template = os.path.join(bootstrap_dir, bt) url = getBootstrapBusinessTemplateUrl(bt)
if not os.path.exists(template): bt = template_tool.download(url)
template = os.path.join(bootstrap_dir, '%s.bt5' % bt) bt.install(**kw)
id = template_tool.generateNewId()
template_tool.download(template, id=id)
template_tool[id].install(**kw)
...@@ -124,7 +124,7 @@ class TemplateTool (BaseTool): ...@@ -124,7 +124,7 @@ class TemplateTool (BaseTool):
"""Get the list of installed business templates. """Get the list of installed business templates.
""" """
installed_bts = [] installed_bts = []
for bt in self.contentValues(filter={'portal_type':'Business Template'}): for bt in self.contentValues(portal_type='Business Template'):
if bt.getInstallationState() == 'installed': if bt.getInstallationState() == 'installed':
installed_bts.append(bt) installed_bts.append(bt)
return installed_bts return installed_bts
...@@ -139,11 +139,22 @@ class TemplateTool (BaseTool): ...@@ -139,11 +139,22 @@ class TemplateTool (BaseTool):
"""Get the list of built and not installed business templates. """Get the list of built and not installed business templates.
""" """
built_bts = [] built_bts = []
for bt in self.contentValues(filter={'portal_type':'Business Template'}): for bt in self.contentValues(portal_type='Business Template'):
if bt.getInstallationState() == 'not_installed' and bt.getBuildingState() == 'built': if bt.getInstallationState() == 'not_installed' and bt.getBuildingState() == 'built':
built_bts.append(bt) built_bts.append(bt)
return built_bts return built_bts
def getLastBusinessTemplateId(self, title):
"""Get the id of the business template with the highest revision number
"""
last_bt = None, None
for bt in self.contentValues(portal_type='Business Template'):
if bt.getTitle() == title and bt.getBuildingState() == 'built':
revision = bt.getRevision()
if last_bt[0] < revision and bt.getInstallationState() != 'deleted':
last_bt = revision, bt.getId()
return last_bt[1]
security.declareProtected(Permissions.ManagePortal, security.declareProtected(Permissions.ManagePortal,
'getDefaultBusinessTemplateDownloadURL') 'getDefaultBusinessTemplateDownloadURL')
def getDefaultBusinessTemplateDownloadURL(self): def getDefaultBusinessTemplateDownloadURL(self):
...@@ -401,6 +412,12 @@ class TemplateTool (BaseTool): ...@@ -401,6 +412,12 @@ class TemplateTool (BaseTool):
name = os.path.normpath(url) name = os.path.normpath(url)
if urltype and urltype != 'file': if urltype and urltype != 'file':
if '/manage_exportObject?' in url:
# In this case, the downloaded BT is already built.
bt = self._p_jar.importFile(urlopen(url))
bt.id = id
del bt.uid
return self[self._setObject(id, bt)]
bt = self._download_url(url, id) bt = self._download_url(url, id)
else: else:
bt = self._download_local(name, id) bt = self._download_local(name, id)
......
...@@ -20,8 +20,9 @@ import traceback ...@@ -20,8 +20,9 @@ import traceback
from cStringIO import StringIO from cStringIO import StringIO
from cPickle import dumps from cPickle import dumps
from glob import glob from glob import glob
from urllib import urlretrieve from urllib import urlopen
from warnings import warn from warnings import warn
from ZTUtils import make_query
# XXX make sure that get_request works. # XXX make sure that get_request works.
current_app = None current_app = None
...@@ -386,56 +387,42 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -386,56 +387,42 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
self.run(*args, **kw) self.run(*args, **kw)
def _getBTPathAndIdList(self, template_list): @staticmethod
INSTANCE_HOME = os.environ['INSTANCE_HOME'] def _getBTPathAndIdList(template_list):
erp5_tests_bt5_path = os.environ.get('erp5_tests_bt5_path', bootstrap_path = os.environ.get('erp5_tests_bootstrap_path') or \
os.path.join(INSTANCE_HOME, 'bt5')) ERP5Site.getBootstrapDirectory()
erp5_product_path = os.path.dirname(Products.ERP5.__file__) bt5_path = os.environ.get('erp5_tests_bt5_path')
bootstrap_path = os.environ.get('erp5_tests_bootstrap_path', if bt5_path:
os.path.join(erp5_product_path, bt5_path_list = bt5_path.split(',')
'bootstrap')) else:
bt5_path = os.path.join(os.environ['INSTANCE_HOME'], 'bt5')
bt5_path_list = bt5_path, os.path.join(bt5_path, '*')
not_found_list = []
new_template_list = [] new_template_list = []
for template in template_list: for template in template_list:
id = template.split('/')[-1] id = template.split('/')[-1]
try : for path in bt5_path_list:
file, headers = urlretrieve(template) if path.endswith('/portal_templates'):
except IOError : bt_id = urlopen('%s/getLastBusinessTemplateId?title=%s'
# First, try the bt5 directory itself. % (path, template)).read()
original_template = template path = bt_id and '%s/manage_exportObject?%s' % (path,
for bt5_path in erp5_tests_bt5_path.split(','): make_query(id=bt_id, download=1, to_xml=0))
template = original_template
path = os.path.join(bt5_path, template)
alternate_path = os.path.join(bootstrap_path, template)
if os.path.exists(path):
template = path
break
elif os.path.exists(alternate_path):
template = alternate_path
break
else: else:
path = '%s.bt5' % path path = os.path.join(path, template)
if os.path.exists(path): path_list = glob(path) + glob(path + '.bt5')
template = path path = path_list and path_list[0]
if path:
break break
else: else:
# Otherwise, look at sub-directories. path = os.path.join(bootstrap_path, template)
# This is for backward-compatibility. if not os.path.exists(path):
path = os.path.join(INSTANCE_HOME, 'bt5', '*', template) not_found_list.append(template)
template_list = glob(path) continue
if len(template_list) == 0: new_template_list.append((path, id))
template_list = glob('%s.bt5' % path) if not_found_list:
if len(template_list) and template_list[0]: raise RuntimeError("Following BT can't be found on your system : %s"
template = template_list[0] % ', '.join(not_found_list))
else:
# The last resort is current directory.
template = '%s' % id
if not os.path.exists(template):
template = '%s.bt5' % id
else:
template = '%s' % template
if not os.path.exists(template):
template = '%s.bt5' % template
new_template_list.append((template,id))
return new_template_list return new_template_list
def manuallyInstallBusinessTemplate(self, *template_list): def manuallyInstallBusinessTemplate(self, *template_list):
...@@ -500,7 +487,6 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -500,7 +487,6 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
if re.search(expression, business_template): if re.search(expression, business_template):
matching_template_list.append(business_template) matching_template_list.append(business_template)
template_list = matching_template_list template_list = matching_template_list
new_template_list = self._getBTPathAndIdList(template_list)
# keep a mapping type info name -> property sheet list, to remove them in # keep a mapping type info name -> property sheet list, to remove them in
# tear down. # tear down.
...@@ -508,7 +494,7 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -508,7 +494,7 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
light_install = self.enableLightInstall() light_install = self.enableLightInstall()
create_activities = self.enableActivityTool() create_activities = self.enableActivityTool()
hot_reindexing = self.enableHotReindexing() hot_reindexing = self.enableHotReindexing()
self.setUpERP5Site(business_template_list=new_template_list, self.setUpERP5Site(business_template_list=template_list,
light_install=light_install, light_install=light_install,
create_activities=create_activities, create_activities=create_activities,
quiet=install_bt5_quiet, quiet=install_bt5_quiet,
...@@ -838,25 +824,16 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -838,25 +824,16 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
def _installBusinessTemplateList(self, business_template_list, def _installBusinessTemplateList(self, business_template_list,
light_install=True, light_install=True,
quiet=True): quiet=True):
portal = self.portal template_tool = self.portal.portal_templates
update_business_templates = os.environ.get('update_business_templates') is not None update_business_templates = os.environ.get('update_business_templates') is not None
BusinessTemplate_getModifiedObject = aq_base(getattr(portal, 'BusinessTemplate_getModifiedObject', None)) BusinessTemplate_getModifiedObject = aq_base(
getattr(self.portal, 'BusinessTemplate_getModifiedObject', None))
# check that all bt5 exist, saving time in case of missing bt
missing_bt_list = []
for url, bt_title in business_template_list:
# if the bt is not found, an error is raised
if not portal.portal_templates.assertBtPathExists(url):
missing_bt_list.append(bt_title)
if len(missing_bt_list):
raise RuntimeError("Some BT can't be found on your system : %s"
% ', '.join(missing_bt_list))
# Add some business templates # Add some business templates
for url, bt_title in business_template_list: for url, bt_title in business_template_list:
start = time.time() start = time.time()
get_install_kw = False get_install_kw = False
if bt_title in [x.getTitle() for x in portal.portal_templates.getInstalledBusinessTemplateList()]: if bt_title in [x.getTitle() for x in template_tool.getInstalledBusinessTemplateList()]:
if update_business_templates: if update_business_templates:
if not quiet: if not quiet:
ZopeTestCase._print('Updating %s business template ... ' % bt_title) ZopeTestCase._print('Updating %s business template ... ' % bt_title)
...@@ -867,7 +844,7 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -867,7 +844,7 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
else: else:
if not quiet: if not quiet:
ZopeTestCase._print('Adding %s business template ... ' % bt_title) ZopeTestCase._print('Adding %s business template ... ' % bt_title)
bt = portal.portal_templates.download(url) bt = template_tool.download(url)
if not quiet: if not quiet:
ZopeTestCase._print('(imported in %.3fs) ' % (time.time() - start)) ZopeTestCase._print('(imported in %.3fs) ' % (time.time() - start))
install_kw = None install_kw = None
...@@ -915,6 +892,8 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -915,6 +892,8 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
if not (hasattr(aq_base(app), portal_name) and if not (hasattr(aq_base(app), portal_name) and
setup_done.get(tuple(business_template_list))): setup_done.get(tuple(business_template_list))):
setup_done[tuple(business_template_list)] = 1 setup_done[tuple(business_template_list)] = 1
business_template_list = \
self._getBTPathAndIdList(business_template_list)
try: try:
_start = time.time() _start = time.time()
# Add user and log in # Add user and log in
...@@ -1135,6 +1114,10 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ...@@ -1135,6 +1114,10 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase):
return ResponseWrapper(response, outstream, path) return ResponseWrapper(response, outstream, path)
from Products.ERP5 import ERP5Site
ERP5Site.getBootstrapBusinessTemplateUrl = lambda bt_title: \
ERP5TypeTestCase._getBTPathAndIdList((bt_title,))[0][0]
class ResponseWrapper: class ResponseWrapper:
'''Decorates a response object with additional introspective methods.''' '''Decorates a response object with additional introspective methods.'''
......
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