Commit 80fc64b9 authored by Aurel's avatar Aurel

initial upload of archive tool


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@16126 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent ff86adcc
......@@ -50,7 +50,7 @@ from MethodObject import Method
from Products.ERP5Security.ERP5UserManager import SUPER_USER
import os, time, urllib, warnings
from zLOG import LOG, PROBLEM
from zLOG import LOG, PROBLEM, INFO
SECURITY_USING_NUX_USER_GROUPS, SECURITY_USING_PAS = range(2)
try:
......@@ -74,6 +74,9 @@ try:
except ImportError:
pass
from Persistence import Persistent
from Acquisition import Implicit
def getSecurityProduct(acl_users):
"""returns the security used by the user folder passed.
(NuxUserGroup, ERP5Security, or None if anything else).
......@@ -83,6 +86,7 @@ def getSecurityProduct(acl_users):
elif acl_users.meta_type == NUG_meta_type:
return SECURITY_USING_NUX_USER_GROUPS
class IndexableObjectWrapper(CMFCoreIndexableObjectWrapper):
def __setattr__(self, name, value):
......@@ -187,6 +191,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
id = 'portal_catalog'
meta_type = 'ERP5 Catalog'
security = ClassSecurityInfo()
default_result_limit = 1000
manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' },
......@@ -204,6 +209,29 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
, 'manage_schema' )
manage_schema = DTMLFile( 'dtml/manageSchema', globals() )
def getPreferredSQLCatalogId(self, id=None):
"""
Get the SQL Catalog from preference.
"""
if id is None:
# Check if we want to use an archive
#if getattr(aq_base(self.portal_preferences), 'uid', None) is not None:
archive_path = self.portal_preferences.getPreferredArchive(sql_catalog_id=self.default_sql_catalog_id)
if archive_path not in ('', None):
try:
archive = self.restrictedTraverse(archive_path)
except KeyError:
# Do not fail if archive object has been removed,
# but preference is not up to date
return None
if archive is not None:
catalog_id = archive.getCatalogId()
if catalog_id not in ('', None):
return catalog_id
return None
else:
return id
security.declareProtected( 'Import/Export objects', 'addDefaultSQLMethods' )
def addDefaultSQLMethods(self, config_id='erp5'):
"""
......@@ -401,7 +429,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
security.declarePublic( 'getAllowedRolesAndUsers' )
def getAllowedRolesAndUsers(self, **kw):
def getAllowedRolesAndUsers(self, sql_catalog_id=None, **kw):
"""
Return allowed roles and users.
......@@ -419,7 +447,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
user_is_superuser = (user_str == SUPER_USER)
allowedRolesAndUsers = self._listAllowedRolesAndUsers(user)
role_column_dict = {}
column_map = self.getSQLCatalog().getColumnMap()
column_map = self.getSQLCatalog(sql_catalog_id).getColumnMap()
# Patch for ERP5 by JP Smets in order
# to implement worklists and search of local roles
......@@ -464,7 +492,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
return allowedRolesAndUsers, role_column_dict
def getSecurityUidListAndRoleColumnDict(self, **kw):
def getSecurityUidListAndRoleColumnDict(self, sql_catalog_id=None, **kw):
"""
Return a list of security Uids and a dictionnary containing available
role columns.
......@@ -474,7 +502,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
catalogs.
"""
allowedRolesAndUsers, role_column_dict = self.getAllowedRolesAndUsers(**kw)
catalog = self.getSQLCatalog()
catalog = self.getSQLCatalog(sql_catalog_id)
method = getattr(catalog, catalog.sql_search_security, None)
if method is None:
raise DeprecationWarning, "The usage of allowedRolesAndUsers is "\
......@@ -501,7 +529,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
return security_uid_list, role_column_dict
security.declarePublic( 'getSecurityQuery' )
def getSecurityQuery(self, query=None, **kw):
def getSecurityQuery(self, query=None, sql_catalog_id=None, **kw):
"""
Build a query based on allowed roles or on a list of security_uid
values. The query takes into account the fact that some roles are
......@@ -509,10 +537,10 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
"""
original_query = query
try:
security_uid_list, role_column_dict = self.getSecurityUidListAndRoleColumnDict(**kw)
security_uid_list, role_column_dict = self.getSecurityUidListAndRoleColumnDict(sql_catalog_id=sql_catalog_id, **kw)
except DeprecationWarning, message:
warnings.warn(message, DeprecationWarning)
allowedRolesAndUsers, role_column_dict = self.getAllowedRolesAndUsers(**kw)
allowedRolesAndUsers, role_column_dict = self.getAllowedRolesAndUsers(sql_catalog_id=sql_catalog_id, **kw)
if role_column_dict:
query_list = []
for key, value in role_column_dict.items():
......@@ -557,9 +585,13 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
kw[ 'effective' ] = { 'query' : now, 'range' : 'max' }
kw[ 'expires' ] = { 'query' : now, 'range' : 'min' }
query = self.getSecurityQuery(query=query, **kw)
catalog_id = self.getPreferredSQLCatalogId(kw.pop("sql_catalog_id", None))
query = self.getSecurityQuery(query=query, sql_catalog_id=catalog_id, **kw)
kw.setdefault('limit', self.default_result_limit)
return ZCatalog.searchResults(self, query=query, **kw)
# get catalog from preference
#LOG("searchResult", INFO, catalog_id)
# LOG("searchResult", INFO, ZCatalog.searchResults(self, query=query, sql_catalog_id=catalog_id, src__=1, **kw))
return ZCatalog.searchResults(self, query=query, sql_catalog_id=catalog_id, **kw)
__call__ = searchResults
......@@ -609,10 +641,11 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
# now = DateTime()
# #kw[ 'effective' ] = { 'query' : now, 'range' : 'max' }
# #kw[ 'expires' ] = { 'query' : now, 'range' : 'min' }
query = self.getSecurityQuery(query=query, **kw)
catalog_id = self.getPreferredSQLCatalogId(kw.pop("sql_catalog_id", None))
query = self.getSecurityQuery(query=query, sql_catalog_id=catalog_id, **kw)
kw.setdefault('limit', self.default_result_limit)
return ZCatalog.countResults(self, query=query, **kw)
# get catalog from preference
return ZCatalog.countResults(self, query=query, sql_catalog_id=catalog_id, **kw)
security.declarePrivate('unrestrictedCountResults')
def unrestrictedCountResults(self, REQUEST=None, **kw):
......@@ -824,4 +857,6 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
InitializeClass(CatalogTool)
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Aurélien Calonne <aurel@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import PropertySheet, Permissions, Interface
from Globals import InitializeClass
from Products.ERP5.Document.Predicate import Predicate
class Archive(Predicate):
"""
A Catalog Archive object
It defines the date of the archive and the catalog to use
"""
meta_type = 'ERP5 Archive'
portal_type = 'Archive'
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces
__implements__ = ( Interface.Predicate, )
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.Archive
)
isIndexable = 1
InitializeClass(Archive)
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Aurélien Calonne <aurel@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class Archive:
"""
"""
_properties = (
{ 'id' : 'catalog_id',
'description' : 'The id of the catalog used by the archive',
'type' : 'string',
'mode' : 'w' },
{ 'id' : 'connection_id',
'description' : 'The id of the connection used by the archive',
'type' : 'string',
'mode' : 'w' },
{ 'id' : 'deferred_connection_id',
'description' : 'The id of the deferred connection used by the archive',
'type' : 'string',
'mode' : 'w' },
{ 'id' : 'priority',
'description' : 'Priority of activity use to index object into the archive',
'type' : 'int',
'mode' : 'w' ,
'default' : 5},
{ 'id' : 'stop_date',
'description' : 'The stop date at which we archive document',
'type' : 'date',
'range' : True,
'default' : None,
'mode' : 'w' },
{ 'id' : 'inventory_method_id',
'description' : 'The method that will be used to create inventory when creating archive',
'type' : 'string',
'mode' : 'w' },
)
#############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Aurélien Calonne <aurel@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class CatalogPreference:
"""
This property sheet defines the user preference for catalog.
"""
_properties = (
{ 'id' : 'preferred_archive',
'description' : 'The archive the user want to use',
'type' : 'string',
'preference' : 1,
'mode' : '' },
)
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Aurelien Calonne <aurel@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass, DTMLFile
from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions
from Products.ERP5Type.Cache import CachingMethod, clearCache
from Products.ERP5Catalog import _dtmldir
from zLOG import LOG, INFO
class ArchiveTool(BaseTool):
"""
Archive Tool contains archive objects
"""
title = 'Archive Tool'
id = 'portal_archives'
meta_type = 'ERP5 Archive Tool'
portal_type = 'Archive Tool'
allowed_types = ('ERP5 Archive',)
# Declarative Security
security = ClassSecurityInfo()
security.declareProtected(Permissions.ManagePortal, 'manage_overview' )
manage_overview = DTMLFile( 'explainArchiveTool', _dtmldir)
def getSQLCatalogIdList(self):
"""
Wrapper to CatalogTool method
"""
return self.portal_catalog.getSQLCatalogIdList()
def SQLConnectionIDs(self):
"""
Wrapper to CatalogTool method
"""
return self.portal_catalog.SQLConnectionIDs()
def getArchiveIdList(self):
"""
Return list of usable archive displayed to user
"""
return ["%s - %s" %(x.getId(), x.getTitle()) for x in \
self.portal_catalog(portal_type="Archive",
validation_state="ready")]
def getArchiveList(self):
"""
Return the list of archive use by catalog
"""
def _getArchiveList():
return [x.getPath() for x in self.objectValues() if x.getValidationState() == "validated"]
# getArchiveList = CachingMethod(_getArchiveList,
# id='getArchiveList',
# cache_factory='erp5_content_short')
return _getArchiveList()
def manage_archive(self, destination_archive_id,
archive_id,
update_destination_sql_catalog=None,
update_archive_sql_catalog=None,
clear_destination_sql_catalog=None,
clear_archive_sql_catalog=None,
REQUEST=None, RESPONSE=None):
"""
This method is used to populate an archive from the current catalog
It is base on hot reindexing, we start from a current catalog
in order to create a new current catalog plus an archive catalog.
Archives are defined in portal_archives, they are predicate thus
we use test method to know in which catalog objects must go.
At the end it creates inventories in order to have
consistent data within the new catalog
"""
# First check parameter for destination catalog
if destination_archive_id == archive_id:
raise ValueError, "Archive and destination archive can't be the same"
portal_catalog =self.portal_catalog
# Guess connection id from current catalog
source_catalog = portal_catalog.getSQLCatalog()
source_catalog_id = source_catalog.getId()
source_connection_id = None
source_deferred_connection_id = None
for method in source_catalog.objectValues():
if method.meta_type == "Z SQL Method":
if 'deferred' in method.connection_id:
source_deferred_connection_id = method.connection_id
elif 'transactionless' not in method.connection_id:
source_connection_id = method.connection_id
if source_connection_id is not None and \
source_deferred_connection_id is not None:
break
if source_connection_id is None or source_deferred_connection_id is None:
raise ValueError, "Unable to determine connection id for the current catalog"
# Get destination property from archive
destination_archive_id = destination_archive_id.split(' - ')[0]
destination_archive = self._getOb(destination_archive_id)
destination_sql_catalog_id = destination_archive.getCatalogId()
destination_connection_id = destination_archive.getConnectionId()
destination_deferred_connection_id = destination_archive.getDeferredConnectionId()
# Get archive property from archive
archive_id = archive_id.split(' - ')[0]
archive = self._getOb(archive_id)
archive_sql_catalog_id = archive.getCatalogId()
archive_connection_id = archive.getConnectionId()
archive_deferred_connection_id = archive.getDeferredConnectionId()
# Check we don't use same connection id for source and destination
if destination_sql_catalog_id == source_catalog_id:
raise ValueError, "Destination and source catalog can't be the same"
if destination_connection_id == source_connection_id:
raise ValueError, "Destination and source connection can't be the same"
if destination_deferred_connection_id == source_deferred_connection_id:
raise ValueError, "Destination and source deferred connection can't be the same"
# Same for source and archive
if archive_sql_catalog_id == source_catalog_id:
raise ValueError, "Archive and source catalog can't be the same"
if archive_connection_id == source_connection_id:
raise ValueError, "Archive and source connection can't be the same"
if archive_deferred_connection_id == source_deferred_connection_id:
raise ValueError, "Archive and source deferred connection can't be the same"
# Same for destination and archive
if archive_sql_catalog_id == destination_sql_catalog_id:
raise ValueError, "Archive and destination catalog can't be the same"
if archive_connection_id == destination_connection_id:
raise ValueError, "Archive and destination connection can't be the same"
if archive_deferred_connection_id == destination_deferred_connection_id:
raise ValueError, "Archive and destination deferred connection can't be the same"
# Update connection id in destination and archive catalog if asked
destination_sql_catalog = getattr(portal_catalog, destination_sql_catalog_id)
if update_destination_sql_catalog:
sql_connection_id_dict = {source_connection_id : destination_connection_id,
source_deferred_connection_id : destination_deferred_connection_id}
portal_catalog.changeSQLConnectionIds(destination_sql_catalog,
sql_connection_id_dict)
archive_sql_catalog = getattr(portal_catalog, archive_sql_catalog_id)
if update_archive_sql_catalog:
sql_connection_id_dict = {source_connection_id : archive_connection_id,
source_deferred_connection_id : archive_deferred_connection_id}
portal_catalog.changeSQLConnectionIds(archive_sql_catalog,
sql_connection_id_dict)
# Clear destination and archive catalog if asked
if clear_destination_sql_catalog:
portal_catalog.manage_catalogClear(sql_catalog_id=destination_sql_catalog_id)
if clear_archive_sql_catalog:
portal_catalog.manage_catalogClear(sql_catalog_id=archive_sql_catalog_id)
# validate archive
archive.validate()
destination_archive.validate()
# Call hot reindexing
portal_catalog.manage_hotReindexAll(source_sql_catalog_id=source_catalog_id,
destination_sql_catalog_id=destination_sql_catalog_id,
archive=archive,
source_sql_connection_id_list=[source_connection_id, source_deferred_connection_id],
destination_sql_connection_id_list=[destination_connection_id, destination_deferred_connection_id],
REQUEST=REQUEST, RESPONSE=RESPONSE)
# Create inventory just before finish of hot reindexing
inventory_date = "%s 23:59:59" %str(archive.getStopDateRangeMax().Date())
LOG("inventory_date", 300, inventory_date)
self.activate(passive_commit=1,
after_method_id=('playBackRecordedObjectList'),
priority=5).runInventoryMethod(archive.id,
source_connection_id,
destination_sql_catalog_id,
inventory_date
)
if RESPONSE is not None:
URL1 = REQUEST.get('URL1')
RESPONSE.redirect(URL1 + '/portal_archives?portal_status_message=Archiving%20Started')
def runInventoryMethod(self, archive_id, source_connection_id, destination_sql_catalog_id, inventory_date):
"""
Use a specific method to create inventory in order to use
activity to execute it
"""
#destination_sql_catalog = getattr(self.portal_catalog, destination_sql_catalog_id)
archive = self._getOb(archive_id)
inventory_method_id = archive.getInventoryMethodId()
inventory_method = getattr(archive, inventory_method_id, None)
if inventory_method is not None:
inventory_method(source_connection_id, destination_sql_catalog_id, inventory_date, tag='runInventoryMethod')
InitializeClass(ArchiveTool)
......@@ -37,9 +37,11 @@ this_module = sys.modules[ __name__ ]
document_classes = updateGlobals( this_module, globals(), permissions_module = Permissions)
# Define object classes and tools
from Tool import ArchiveTool
import CatalogTool
object_classes = ()
portal_tools = (CatalogTool.CatalogTool,)
portal_tools = (CatalogTool.CatalogTool,
ArchiveTool.ArchiveTool)
content_classes = ()
content_constructors = ()
......
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<h3> <code>portal_archives</code> Tool </h3>
<p> This tool is used to stored archives object which are predicate
that tells in which catalog an object must go.
</p>
<dtml-var manage_page_footer>
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Aurlien Calonne <aurel@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
# Needed in order to have a log file inside the current folder
os.environ['EVENT_LOG_FILE'] = os.path.join(os.getcwd(), 'zLOG.log')
os.environ['EVENT_LOG_SEVERITY'] = '-300'
from Testing import ZopeTestCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from AccessControl import getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager
from zLOG import LOG
from DateTime import DateTime
from Products.CMFCore.tests.base.testcase import LogInterceptor
from Testing.ZopeTestCase.PortalTestCase import PortalTestCase
from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.ZSQLCatalog.ZSQLCatalog import HOT_REINDEXING_FINISHED_STATE,\
HOT_REINDEXING_RECORDING_STATE, HOT_REINDEXING_DOUBLE_INDEXING_STATE
from Products.CMFActivity.Errors import ActivityFlushError
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
from Products.ERP5.tests.testInventoryAPI import InventoryAPITestCase
from DateTime import DateTime
try:
from transaction import get as get_transaction
except ImportError:
pass
class TestArchive(InventoryAPITestCase):
"""
Tests for Archive.
"""
def getTitle(self):
return "ERP5Archive"
def getBusinessTemplateList(self):
return ('erp5_base',
'erp5_trade',
'erp5_apparel',
'erp5_dummy_movement',
'erp5_archive',
)
# Different variables used for this test
run_all_test = 0
quiet = 1
def afterSetUp(self):
self.login()
InventoryAPITestCase.afterSetUp(self)
# make sure there is no message any more
self.tic()
def beforeTearDown(self):
for module in [ self.getPersonModule(),
self.getOrganisationModule(),
self.getCategoryTool().region,
self.getCategoryTool().group ]:
module.manage_delObjects(list(module.objectIds()))
self.getPortal().portal_activities.manageClearActivities()
get_transaction().commit()
def login(self):
uf = self.getPortal().acl_users
uf._doAddUser('seb', '', ['Manager'], [])
user = uf.getUserById('seb').__of__(uf)
newSecurityManager(None, user)
def getSQLPathList(self,connection_id=None):
"""
Give the full list of path in the catalog
"""
if connection_id is None:
sql_connection = self.getSQLConnection()
else:
sql_connection = getattr(self.getPortal(),connection_id)
sql = 'select path from catalog'
result = sql_connection.manage_test(sql)
path_list = map(lambda x: x['path'],result)
return path_list
def checkRelativeUrlInSQLPathList(self,url_list,connection_id=None):
path_list = self.getSQLPathList(connection_id=connection_id)
portal_id = self.getPortalId()
for url in url_list:
path = '/' + portal_id + '/' + url
#LOG('checkRelativeUrlInSQLPathList found path:',0,path)
self.failUnless(path in path_list)
def checkRelativeUrlNotInSQLPathList(self,url_list,connection_id=None):
path_list = self.getSQLPathList(connection_id=connection_id)
portal_id = self.getPortalId()
for url in url_list:
path = '/' + portal_id + '/' + url
#LOG('checkRelativeUrlInSQLPathList not found path:',0,path)
self.failUnless(path not in path_list)
def test_Archive(self, quiet=quiet, run=1): #run_all_test):
if not run: return
if not quiet:
message = 'Archive'
ZopeTestCase._print('\n%s ' % message)
LOG('Testing... ',0,message)
portal = self.getPortal()
portal_category = self.getCategoryTool()
portal_activities = self.getActivityTool()
portal_archive = self.getArchiveTool()
portal_catalog = self.getCatalogTool()
# Create some objects
self.base_category = portal_category.newContent(portal_type='Base Category',
title="GreatTitle1")
module = portal.getDefaultModule('Organisation')
self.organisation = module.newContent(portal_type='Organisation',
title="GreatTitle2")
getInventory = self.getSimulationTool().getInventory
self.mvt = self._makeMovement(quantity=100, stop_date=DateTime("2006/06/06"),
simulation_state='delivered',)
self.assertEquals(100, getInventory(node_uid=self.node.getUid()))
self.assertEqual(len(self.folder.searchFolder(portal_type="Dummy Movement")), 1)
# Flush message queue
get_transaction().commit()
self.tic()
# Check well in catalog
self.original_connection_id = 'erp5_sql_connection'
self.original_deferred_connection_id = 'erp5_sql_deferred_connection'
path_list = [self.organisation.getRelativeUrl()]
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.original_connection_id)
# Create new connectors for destination
self.new_connection_id = 'erp5_sql_connection1'
portal.manage_addZMySQLConnection(self.new_connection_id,'',
'test2 test2')
new_connection = portal[self.new_connection_id]
new_connection.manage_open_connection()
# the deferred one
self.new_deferred_connection_id = 'erp5_sql_connection2'
portal.manage_addZMySQLConnection(self.new_deferred_connection_id,'',
'test2 test2')
new_deferred_connection = portal[self.new_deferred_connection_id]
new_deferred_connection.manage_open_connection()
# Create new connectors for archive
self.archive_connection_id = 'erp5_sql_connection3'
portal.manage_addZMySQLConnection(self.archive_connection_id,'',
'test3 test3')
archive_connection = portal[self.archive_connection_id]
archive_connection.manage_open_connection()
# the deferred one
self.archive_deferred_connection_id = 'erp5_sql_connection4'
portal.manage_addZMySQLConnection(self.archive_deferred_connection_id,'',
'test3 test3')
archive_deferred_connection = portal[self.archive_deferred_connection_id]
archive_deferred_connection.manage_open_connection()
# Create new catalog for destination
self.original_catalog_id = 'erp5_mysql_innodb'
self.new_catalog_id = self.original_catalog_id + '_2'
cp_data = portal_catalog.manage_copyObjects(ids=('erp5_mysql_innodb',))
new_id = portal_catalog.manage_pasteObjects(cp_data)[0]['new_id']
new_catalog_id = 'erp5_mysql_innodb_2'
portal_catalog.manage_renameObject(id=new_id,new_id=new_catalog_id)
dest_catalog = portal_catalog[new_catalog_id]
# Create new catalog for archive
self.archive_catalog_id = self.original_catalog_id + '_archive'
cp_data = portal_catalog.manage_copyObjects(ids=('erp5_mysql_innodb',))
archive_id = portal_catalog.manage_pasteObjects(cp_data)[0]['new_id']
archive_catalog_id = 'erp5_mysql_innodb_archive'
portal_catalog.manage_renameObject(id=archive_id,new_id=archive_catalog_id)
archive_catalog = portal_catalog[archive_catalog_id]
# Create an archive
archive = portal_archive.newContent(portal_typ="Archive",
catalog_id=self.archive_catalog_id,
connection_id=self.archive_connection_id,
deferred_connection_id=self.archive_deferred_connection_id,
priority=3,
inventory_method_id='Archive_createAllInventory',
test_method_id='Archive_test',
stop_date_range_min=DateTime("2006/06/01"),
stop_date_range_max=DateTime("2006/07/01"),
)
archive.ready()
# Create an archive for destination catalog
dest = portal_archive.newContent(portal_typ="Archive",
catalog_id=self.new_catalog_id,
connection_id=self.new_connection_id,
deferred_connection_id=self.new_deferred_connection_id,
priority=1,
test_method_id='Archive_test',
stop_date_range_min=DateTime("2006/07/01"),
)
dest.ready()
# Do archive
portal_archive.manage_archive(destination_archive_id=dest.getId(),
archive_id=archive.getId(),
update_destination_sql_catalog=True,
update_archive_sql_catalog=True,
clear_destination_sql_catalog=True,
clear_archive_sql_catalog=True)
get_transaction().commit()
self.tic()
self.assertEqual(portal_catalog.getSQLCatalog().id, self.new_catalog_id)
self.assertEqual(archive.getValidationState(), 'validated')
self.assertEqual(dest.getValidationState(), 'validated')
# Check objects organisation are indexed
# in both archive and current catalog and old one
path_list = [self.organisation.getRelativeUrl()]
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.original_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.new_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.archive_connection_id)
# Create a new organisation and check it goes in both catalog and not old one
self.organisation_1 = module.newContent(portal_type='Organisation',
title="GreatTitle3")
get_transaction().commit()
self.tic()
path_list = [self.organisation_1.getRelativeUrl()]
self.checkRelativeUrlNotInSQLPathList(path_list, connection_id=self.original_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.new_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.archive_connection_id)
# Check objects movement are indexed
# in archive and old one and not in current catalog
path_list = [self.mvt.getRelativeUrl()]
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.original_connection_id)
self.checkRelativeUrlNotInSQLPathList(path_list, connection_id=self.new_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.archive_connection_id)
# Create a new movement and check it goes only in new catalog
self.assertEqual(len(self.folder.searchFolder(portal_type="Dummy Movement")), 0)
self.assertEquals(100, getInventory(node_uid=self.node.getUid()))
self.new_mvt = self._makeMovement(quantity=50, stop_date=DateTime("2006/08/06"),
simulation_state='delivered',)
get_transaction().commit()
self.tic()
self.assertEqual(len(self.folder.searchFolder(portal_type="Dummy Movement")), 1)
# Check objects movement are indexed
# not in archive and old one but in current catalog
path_list = [self.new_mvt.getRelativeUrl()]
self.checkRelativeUrlNotInSQLPathList(path_list, connection_id=self.original_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.new_connection_id)
self.checkRelativeUrlNotInSQLPathList(path_list, connection_id=self.archive_connection_id)
self.assertEquals(150, getInventory(node_uid=self.node.getUid()))
# now play with preference to select to view document from archive
portal_preferences = self.getPreferenceTool()
self.pref = portal_preferences.newContent(id='user_pref',
portal_type='Preference',
preferred_archive=archive.getRelativeUrl())
get_transaction().commit()
self.getPreferenceTool().recursiveReindexObject()
self.tic()
self.portal.portal_workflow.doActionFor(self.pref,
'enable_action',
wf_id='preference_workflow')
self.assertEquals(self.pref.getPreferenceState(), 'enabled')
path_list = [self.pref.getRelativeUrl()]
self.checkRelativeUrlNotInSQLPathList(path_list, connection_id=self.original_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.new_connection_id)
self.checkRelativeUrlInSQLPathList(path_list, connection_id=self.archive_connection_id)
self.assertEqual(portal_catalog.getPreferredSQLCatalogId(), archive.getCatalogId())
self.assertEqual(len(self.folder.searchFolder(portal_type="Dummy Movement")), 1)
# As we only have first movement in archive, inventory must be 100
self.assertEquals(100, getInventory(node=self.node.getRelativeUrl()))
if __name__ == '__main__':
framework()
else:
import unittest
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestArchive))
return suite
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