Commit 7d31f4fb authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Component with the same version/reference as a validated one...

ZODB Components: Component with the same version/reference as a validated one must not be able to be validated.
parent a450e310
......@@ -123,7 +123,9 @@ class ComponentDynamicPackage(ModuleType):
# beforehand
if version in version_priority_set:
reference = component.getReference(validated_only=True)
self.__registry_dict.setdefault(reference, {})[version] = component.getId()
self.__registry_dict.setdefault(reference, {})[version] = (
component.getId(),
component.getUid())
return self.__registry_dict
......@@ -281,7 +283,7 @@ class ComponentDynamicPackage(ModuleType):
(fullname, self._namespace, error))
try:
component_id = self._registry_dict[name][version]
component_id = self._registry_dict[name][version][0]
except KeyError:
raise ImportError("%s: version %s of Component %s could not be found" % \
(fullname, version, name))
......@@ -296,8 +298,9 @@ class ComponentDynamicPackage(ModuleType):
# Version priority name list is ordered in descending order
for version in site.getVersionPriorityNameList():
component_id = component_version_dict.get(version)
if component_id is not None:
component_id_uid_tuple = component_version_dict.get(version)
if component_id_uid_tuple is not None:
component_id = component_id_uid_tuple[0]
break
else:
raise ImportError("%s: no version of Component %s in Site priority" % \
......
......@@ -177,6 +177,9 @@ class ComponentMixin(PropertyRecordableMixin, Base):
_message_version_not_set = "Version must be set"
_message_invalid_version = "Version cannot start with '_'"
_message_duplicated_version_reference = "${id} is validated has the same "\
"Reference and Version"
_message_text_content_not_set = "No source code"
_message_text_content_error = "Error in Source Code: ${error_message}"
......@@ -195,9 +198,10 @@ class ComponentMixin(PropertyRecordableMixin, Base):
"""
error_list = super(ComponentMixin, self).checkConsistency(*args, **kw)
object_relative_url = self.getRelativeUrl()
reference = self.getReference()
reference_has_error = False
if not reference:
reference_has_error = True
error_list.append(
ConsistencyMessage(self,
object_relative_url,
......@@ -207,6 +211,7 @@ class ComponentMixin(PropertyRecordableMixin, Base):
elif (reference.endswith('_version') or
reference[0] == '_' or
reference in ('find_module', 'load_module', 'reset')):
reference_has_error = True
error_list.append(
ConsistencyMessage(self,
object_relative_url,
......@@ -224,6 +229,26 @@ class ComponentMixin(PropertyRecordableMixin, Base):
object_relative_url,
message=self._message_invalid_version,
mapping={}))
else:
package = __import__(self._getDynamicModuleNamespace(), globals(),
fromlist=[self._getDynamicModuleNamespace()], level=0)
component_id = None
component_uid = None
from Products.ERP5Type.dynamic import aq_method_lock
with aq_method_lock:
component_id_uid_tuple = package._registry_dict.get(
self.getReference(), {}).get(self.getVersion(), None)
if component_id_uid_tuple:
component_id, component_uid = component_id_uid_tuple
if (component_id is not None and component_uid is not None and
not reference_has_error and
component_uid != self.getUid() and component_id != self.getId()):
error_list.append(
ConsistencyMessage(self,
object_relative_url,
message=self._message_duplicated_version_reference,
mapping=dict(id=component_id)))
text_content = self.getTextContent()
if not text_content:
......
......@@ -1261,12 +1261,23 @@ class _TestZodbComponent(SecurityTestCase):
self._component_tool.reset(force=True,
reset_portal_type_at_transaction_boundary=True)
@abc.abstractmethod
def _newComponent(self, reference, text_content, version='erp5'):
def _newComponent(self, reference, text_content, version='erp5', id_=None):
"""
Abstract method to create a new Component
Create new Component
"""
pass
full_id = '%s.%s.%s' % (self._getComponentModuleName(),
version + '_version',
reference)
if id_ is not None:
full_id += '.%s' % id_
return self._component_tool.newContent(
id=full_id,
version=version,
reference=reference,
text_content=text_content,
portal_type=self._component_portal_type)
@abc.abstractmethod
def _getComponentModuleName(self):
......@@ -1895,6 +1906,45 @@ def bar(*args, **kwargs):
self.assertUserCanModifyDocument(user_id, component)
self.assertUserCanDeleteDocument(user_id, component)
def testValidateComponentWithSameReferenceVersionAlreadyValidated(self):
reference = 'ValidateComponentWithSameReferenceVersionAlreadyValidated'
component = self._newComponent(reference, 'def foo():\n print "ok"')
component.validate()
self.tic()
component_dup = self._newComponent(reference, 'def foo():\n print "ok"',
id_='duplicated')
self.tic()
from Products.DCWorkflow.DCWorkflow import ValidationFailed
self.assertRaises(ValidationFailed,
self.portal.portal_workflow.doActionFor,
component_dup, 'validate_action')
self.assertEquals(component_dup.getValidationState(), 'draft')
component_dup.setReference(reference + '_copy')
component_dup.validate()
self.tic()
component_dup.setReference(reference)
self.tic()
self.assertEquals(component_dup.getValidationState(), 'modified')
self.assertEquals(component_dup.getReference(), reference)
self.assertEquals(component_dup.getReference(validated_only=True),
reference + '_copy')
component_dup.invalidate()
self.tic()
component_dup.setReference(reference)
self.assertRaises(ValidationFailed,
self.portal.portal_workflow.doActionFor,
component_dup, 'validate_action')
self.assertEquals(component_dup.getValidationState(), 'invalidated')
from Products.ERP5Type.Core.ExtensionComponent import ExtensionComponent
class TestZodbExtensionComponent(_TestZodbComponent):
......@@ -1902,15 +1952,7 @@ class TestZodbExtensionComponent(_TestZodbComponent):
Tests specific to ZODB Extension Component (previously defined in bt5 and
installed on the filesystem in $INSTANCE_HOME/Extensions)
"""
def _newComponent(self, reference, text_content, version='erp5'):
return self._component_tool.newContent(
id='%s.%s.%s' % (self._getComponentModuleName(),
version + '_version',
reference),
version=version,
reference=reference,
text_content=text_content,
portal_type='Extension Component')
_component_portal_type = 'Extension Component'
def _getComponentModuleName(self):
return ExtensionComponent._getDynamicModuleNamespace()
......@@ -1987,14 +2029,7 @@ class TestZodbDocumentComponent(_TestZodbComponent):
previously defined in bt5 and installed on the filesystem in
$INSTANCE_HOME/Document. Later on, Product Documents will also be migrated
"""
def _newComponent(self, reference, text_content, version='erp5'):
return self._component_tool.newContent(
id='%s.%s.%s' % (self._getComponentModuleName(),
version + '_version', reference),
reference=reference,
version=version,
text_content=text_content,
portal_type='Document Component')
_component_portal_type = 'Document Component'
def _getComponentModuleName(self):
return DocumentComponent._getDynamicModuleNamespace()
......@@ -2125,14 +2160,7 @@ class TestZodbTestComponent(_TestZodbComponent):
Tests specific to ZODB Test Component (known as Live Tests, and previously
defined in bt5 and installed in $INSTANCE_HOME/test)
"""
def _newComponent(self, reference, text_content, version='erp5'):
return self._component_tool.newContent(
id='%s.%s.%s' % (self._getComponentModuleName(),
version + '_version', reference),
reference=reference,
version=version,
text_content=text_content,
portal_type='Test Component')
_component_portal_type = 'Test Component'
def _getComponentModuleName(self):
return TestComponent._getDynamicModuleNamespace()
......
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