示例#1
0
    def resetDynamicDocuments(self):
        """Resets all dynamic documents: force reloading erp.* classes

    WARNING: COSTLY! Please double-check that
    resetDynamicDocumentsOnceAtTransactionBoundary can't be used instead.
    """
        synchronizeDynamicModules(self, force=True)
示例#2
0
    def resetDynamicDocuments(self):
        """Resets all dynamic documents: force reloading erp.* classes

    WARNING: COSTLY! Please double-check that
    resetDynamicDocumentsOnceAtTransactionBoundary can't be used instead.
    """
        synchronizeDynamicModules(self, force=True)
示例#3
0
  def testAttributeValueComputedFromAccessorHolderList(self):
    """
    Check that attributes such as constraints and _categories,
    containing respectively all the constraints and categories define
    on their Property Sheets, loads the portal type class as some
    static getters (for example getInstanceBaseCategoryList() use
    _categories directly)
    """
    import erp5.portal_type

    synchronizeDynamicModules(self.portal, force=True)
    self.assertTrue(erp5.portal_type.Person.__isghost__)
    self.assertTrue('constraints' not in erp5.portal_type.Person.__dict__)

    getattr(erp5.portal_type.Person, 'constraints')
    self.assertTrue(not erp5.portal_type.Person.__isghost__)
    self.assertTrue('constraints' in erp5.portal_type.Person.__dict__)

    synchronizeDynamicModules(self.portal, force=True)
    self.assertTrue(erp5.portal_type.Person.__isghost__)
    self.assertTrue('_categories' not in erp5.portal_type.Person.__dict__)

    getattr(erp5.portal_type.Person, '_categories')
    self.assertTrue(not erp5.portal_type.Person.__isghost__)
    self.assertTrue('_categories' in erp5.portal_type.Person.__dict__)
示例#4
0
    def reset(self,
              force=False,
              reset_portal_type_at_transaction_boundary=False):
        """
    Reset all ZODB Component packages. A cache cookie is used to check whether
    the reset is necessary when force is not specified. This allows to make
    sure that all ZEO clients get reset (checked in __of__ on ERP5Site) when
    one given ZEO client gets reset when Component(s) are modified or
    invalidated.

    Also, as resetting ZODB Components Package usually implies to reset Portal
    Type as Classes (because the former are used as bases), perform the reset
    by default.

    XXX-arnau: for now, this is a global reset but it might be improved in the
    future if required...
    """
        portal = self.getPortalObject()

        global last_sync
        if force:
            # Hard invalidation to force sync between nodes
            portal.newCacheCookie('component_packages')
            last_sync = portal.getCacheCookie('component_packages')
        else:
            cookie = portal.getCacheCookie('component_packages')
            if cookie == last_sync:
                return False

            last_sync = cookie

        LOG("ERP5Type.Tool.ComponentTool", INFO, "Resetting Components")

        # Make sure that it is not possible to load Components or load Portal Type
        # class when Components are reset through aq_method_lock
        import erp5.component
        from Products.ERP5Type.dynamic.component_package import ComponentDynamicPackage
        with aq_method_lock:
            for package in erp5.component.__dict__.itervalues():
                if isinstance(package, ComponentDynamicPackage):
                    package.reset()

            erp5.component.ref_manager.gc()
        if reset_portal_type_at_transaction_boundary:
            portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary(
            )
        else:
            from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModules
            synchronizeDynamicModules(self, force)

        return True
示例#5
0
  def reset(self,
            force=False,
            reset_portal_type_at_transaction_boundary=False):
    """
    Reset all ZODB Component packages. A cache cookie is used to check whether
    the reset is necessary when force is not specified. This allows to make
    sure that all ZEO clients get reset (checked in __of__ on ERP5Site) when
    one given ZEO client gets reset when Component(s) are modified or
    invalidated.

    Also, as resetting ZODB Components Package usually implies to reset Portal
    Type as Classes (because the former are used as bases), perform the reset
    by default.

    XXX-arnau: for now, this is a global reset but it might be improved in the
    future if required...
    """
    portal = self.getPortalObject()

    global last_sync
    if force:
      # Hard invalidation to force sync between nodes
      portal.newCacheCookie('component_packages')
      last_sync = portal.getCacheCookie('component_packages')
    else:
      cookie = portal.getCacheCookie('component_packages')
      if cookie == last_sync:
        return False

      last_sync = cookie

    LOG("ERP5Type.Tool.ComponentTool", INFO, "Resetting Components")

    # Make sure that it is not possible to load Components or load Portal Type
    # class when Components are reset through aq_method_lock
    import erp5.component
    from Products.ERP5Type.dynamic.component_package import ComponentDynamicPackage
    with aq_method_lock:
      for package in erp5.component.__dict__.itervalues():
        if isinstance(package, ComponentDynamicPackage):
          package.reset()

    if reset_portal_type_at_transaction_boundary:
      portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
    else:
      from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModules
      synchronizeDynamicModules(self, force)

    return True
示例#6
0
  def testConstraintAfterClosingZODBConnection(self):
    """
    Make sure that constraint works even if ZODB connection close.
    This test is added for the bug #20110628-ABAA76.
    """
    # Open new connection and add a new constraint.
    db = self.app._p_jar.db()
    con = db.open()
    app = con.root()['Application'].__of__(self.app.aq_parent)
    portal = app[self.getPortalName()]
    from Products.ERP5.ERP5Site import getSite, setSite
    old_site = getSite()
    setSite(portal)

    import erp5
    dummy = getattr(erp5.portal_type, 'TALES Constraint')(id='dummy')
    portal.portal_property_sheets.TestMigration._setObject('dummy', dummy)
    dummy = portal.portal_property_sheets.TestMigration.dummy
    dummy.edit(reference='test_dummy_constraint',
               expression='python: object.getTitle() == "my_tales_constraint_title"')
    dummy.Predicate_view()

    transaction.commit()

    # Recreate class with a newly added constraint
    synchronizeDynamicModules(portal, force=True)
    # Load test_module
    test_module = getattr(portal, 'Test Migration')
    test_module.objectValues()
    # Then close this new connection.
    transaction.abort()
    con.close()
    # This code depends on ZODB implementation.
    for i in db.pool.available[:]:
      if i[1] == con:
        db.pool.available.remove(i)
    db.pool.all.remove(con)
    del con

    # Back to the default connection.
    transaction.abort()
    self.app._p_jar._resetCache()
    setSite(old_site)

    # Call checkConsistency and make sure that ConnectionStateError does not occur.
    self.assert_(self.test_module.checkConsistency())
示例#7
0
  def testClassHierarchyAfterReset(self):
    """
    Check that after a class reset, the class hierarchy is unchanged until
    un-ghostification happens. This is very important for multithreaded
    environments:
      Thread A. reset dynamic classes
      Thread B. in Folder code for instance: CMFBTreeFolder.method(self)

    If a reset happens before the B) method call, and does not keep the
    correct hierarchy (for instance Folder superclass is removed from
    the mro()), a TypeError might be raised:
      "method expected CMFBTreeFolder instance, got erp5.portal_type.xxx
      instead"

    This used to be broken because the ghost state was only what is called
    lazy_class.InitGhostBase: a "simple" subclass of ERP5Type.Base
    """
    name = "testClassHierarchyAfterReset Module"
    types_tool = self.portal.portal_types

    ptype = types_tool.newContent(id=name, type_class="Folder")
    transaction.commit()
    module_class = types_tool.getPortalTypeClass(name)
    module_class.loadClass()

    # first manually reset and check that everything works
    from Products.ERP5Type.Core.Folder import Folder
    self.assertTrue(issubclass(module_class, Folder))
    synchronizeDynamicModules(self.portal, force=True)
    self.assertTrue(issubclass(module_class, Folder))

    # then change the type value to something not descending from Folder
    # and check behavior
    ptype.setTypeClass('Address')

    # while the class has not been reset is should still descend from Folder
    self.assertTrue(issubclass(module_class, Folder))
    # finish transaction and trigger workflow/DynamicModule reset
    transaction.commit()
    # while the class has not been unghosted it's still a Folder
    self.assertTrue(issubclass(module_class, Folder))
    # but it changes as soon as the class is loaded
    module_class.loadClass()
    self.assertFalse(issubclass(module_class, Folder))
示例#8
0
  def afterSetUp(self):
    """
    Create a test Property Sheet (and its properties)
    """
    portal = self.getPortal()

    # Create the test Property Sheet
    try:
      self.test_property_sheet = portal.portal_property_sheets.TestMigration
      do_create = False
    except AttributeError:
      self.test_property_sheet = \
        portal.portal_property_sheets.newContent(id='TestMigration',
                                                 portal_type='Property Sheet')
      do_create = True

    if do_create:
      # Create a new Standard Property to test constraints and a
      # Property Existence Constraint in the test Property Sheet
      self._newStandardProperty('constraint')
      self._newPropertyExistenceConstraint()

      # Create a Category Existence Constraint in the test Property
      # Sheet
      self._newCategoryExistenceConstraint()

      # Create an Attribute Equality Constraint in the test Property
      # Sheet
      self._newAttributeEqualityConstraint()

      # Create a Content Existence Constraint in the test Property
      # Sheet
      self._newContentExistenceConstraint()

      # Create a Category Membership Arity Constraint without
      # acquisition in the test Property Sheet
      self._newCategoryMembershipArityConstraint(
        'test_category_membership_arity_constraint')

      # Create a Category Membership Arity Constraint with acquisition
      # in the test Property Sheet
      self._newCategoryMembershipArityConstraint(
        'test_category_membership_arity_constraint_with_acquisition',
        use_acquisition=True)

      # Create a Category Related Membership Arity Constraint in the
      # test Property Sheet
      self._newCategoryRelatedMembershipArityConstraint()

      # Create a TALES Constraint in the test Property Sheet
      self._newTALESConstraint()

      # Create a Property Type Validity Constraint in the test Property Sheet
      self._newPropertyTypeValidityConstraint()

      # Create all the test Properties
      for operation_type in ('change', 'delete', 'assign'):
        self._newStandardProperty(operation_type)
        self._newAcquiredProperty(operation_type)
        self._newCategoryProperty(operation_type)
        self._newDynamicCategoryProperty(operation_type)

    # Bind all test properties to this instance, so they can be
    # accessed easily in further tests
    for property in self.test_property_sheet.contentValues():
      setattr(self, property.getReference(), property)

    # Create a Portal Type for the tests, this is necessary, otherwise
    # there will be no accessor holder generated
    try:
      self.test_portal_type = getattr(portal.portal_types, 'Test Migration')
    except AttributeError:
      self.test_portal_type = portal.portal_types.newContent(
        id='Test Migration',
        portal_type='Base Type',
        type_class='Folder',
        type_property_sheet_list=('TestMigration',),
        type_base_category_list=('test_category_existence_constraint',),
        type_filter_content_type=False)
    # Create a Portal Type for subobject of Test Migration
    try:
      self.test_subobject_portal_type = getattr(portal.portal_types, 'Test Document')
    except AttributeError:
      self.test_subobject_portal_type = portal.portal_types.newContent(
        id='Test Document',
        portal_type='Base Type',
        type_class='Folder',
        type_filter_content_type=False)
      self.test_portal_type.setTypeAllowedContentTypeList(['Test Document'])

    # Create a test module, meaningful to force generation of
    # TestMigration accessor holders and check the constraints
    try:
      self.test_module = getattr(portal, 'Test Migration')
    except AttributeError:
      self.test_module = portal.newContent(id='Test Migration',
                                           portal_type='Test Migration')

    # Make sure there is no pending transaction which could interfere
    # with the tests
    transaction.commit()
    self.tic()

    # Ensure that erp5.acessor_holder is empty
    synchronizeDynamicModules(portal, force=True)
    def test_00_updateBusinessTemplateFromUrl_simple(self):
        """
     Test updateBusinessTemplateFromUrl method

     By default if a new business template has revision != previous one
     the new bt5 is not installed, only imported.
    """
        self._svn_setup_ssl()
        # we make this class a global so that it can be pickled
        global PropertiesTool  # pylint:disable=global-variable-not-assigned

        class PropertiesTool(ActionsTool):  # pylint:disable=redefined-outer-name
            id = 'portal_properties'

        cls = PropertiesTool

        # Assign a fake properties tool to the portal
        tool = PropertiesTool()
        self.portal._setObject(tool.id,
                               tool,
                               set_owner=False,
                               suppress_events=True)
        del tool
        self.commit()

        template_tool = self.portal.portal_templates

        url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/erp5_csv_style'
        template_tool.updateBusinessTemplateFromUrl(url)
        old_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
        # fake different revision
        old_bt.setRevision('')

        # Break the properties tool
        self.assertIs(self.portal.portal_properties.__class__, cls)
        self.commit()
        self.portal._p_jar.cacheMinimize()
        del PropertiesTool
        self.assertIsNot(self.portal.portal_properties.__class__, cls)

        # Remove portal.portal_properties
        from Products.ERP5Type.dynamic.portal_type_class import \
          _bootstrapped, synchronizeDynamicModules
        _bootstrapped.remove(self.portal.id)
        synchronizeDynamicModules(self.portal, force=True)

        # The bt from this repo
        url = self._getBTPathAndIdList(('erp5_csv_style', ))[0][0]

        new_bt = template_tool.updateBusinessTemplateFromUrl(url)
        self.assertNotEquals(old_bt, new_bt)
        self.assertEqual('erp5_csv_style', new_bt.getTitle())

        # Test Another time with definning an ID
        old_bt = new_bt
        old_bt.setRevision('')
        template_tool.updateBusinessTemplateFromUrl(url,
                                                    id="new_erp5_csv_style")
        new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
        self.assertNotEquals(old_bt, new_bt)
        self.assertEqual('erp5_csv_style', new_bt.getTitle())
        self.assertEqual('new_erp5_csv_style', new_bt.getId())

        # Test if the new instance with same revision is not installed.
        old_bt = new_bt
        template_tool.updateBusinessTemplateFromUrl(url,
                                                    id="not_installed_bt5")
        new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
        self.assertEqual(old_bt, new_bt)
        self.assertEqual('erp5_csv_style', new_bt.getTitle())
        self.assertEqual('new_erp5_csv_style', new_bt.getId())
        not_installed_bt5 = template_tool['not_installed_bt5']
        self.assertEqual('erp5_csv_style', not_installed_bt5.getTitle())
        self.assertEqual(not_installed_bt5.getInstallationState(),
                         "not_installed")
        self.assertEqual(not_installed_bt5.getRevision(), new_bt.getRevision())