Ignore:
Timestamp:
26 Nov 2012, 23:27:46 (12 years ago)
Author:
uli
Message:

Add VirtualExportJobContainers? for storing export jobs in a central exports container.

Location:
main/waeup.kofa/trunk/src/waeup/kofa
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py

    r9718 r9726  
    12171217        Returns ``None`` if no such entry can be found.
    12181218        """
     1219
     1220class IExportContainerFinder(Interface):
     1221    """A finder for the central export container.
     1222    """
     1223    def __call__():
     1224        """Return the currently used global or site-wide IExportContainer.
     1225        """
  • main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py

    r9718 r9726  
    3232from zope.component import createObject, getUtility
    3333from zope.component.hooks import setSite
    34 from zope.interface import Interface
     34from zope.interface import Interface, implementer
    3535from zope.schema import getFields
    3636from zope.event import notify
     
    3939    IBatchProcessor, FatalCSVError, IObjectConverter, IJobManager,
    4040    ICSVExporter, IGNORE_MARKER, DuplicationError, JOB_STATUS_MAP,
    41     IExportJobContainer, IExportJob)
     41    IExportJobContainer, IExportJob, IExportContainerFinder)
    4242
    4343class BatchProcessor(grok.GlobalUtility):
     
    672672                return entry
    673673        return None
     674
     675class VirtualExportJobContainer(ExportJobContainer):
     676    """A virtual export job container.
     677
     678    Virtual ExportJobContainers can be used as a mixin just like real
     679    ExportJobContainer.
     680
     681    They retrieve and store data in the site-wide ExportJobContainer.
     682
     683    Functionality is currently entirely as for regular
     684    ExportJobContainers, except that data is stored elsewhere.
     685
     686    VirtualExportJobContainers need a registered
     687    IExportContainerFinder utility to find a suitable container for
     688    storing data.
     689    """
     690    grok.implements(IExportJobContainer)
     691
     692    @property
     693    def _site_container(self):
     694        return getUtility(IExportContainerFinder)()
     695
     696    # The following is a simple trick. While ExportJobContainers store
     697    # only one attribute in ZODB, it is sufficient to replace this
     698    # attribute `running_exports` with a suitable manager to make the
     699    # whole virtual container work like the original but with the data
     700    # stored in the site-wide exports container. This way, virtual
     701    # export containers provide the whole functionality of a regular
     702    # exports container but store no data at all with themselves.
     703    @property
     704    def running_exports(self):
     705        """Exports stored in the site-wide exports container.
     706        """
     707        return self._site_container.running_exports
     708
     709    @running_exports.setter
     710    def running_exports(self, value):
     711        self._site_container.running_exports = value
     712
     713    @running_exports.deleter
     714    def running_exports(self):
     715        del self._site_container.running_exports
     716
     717
     718@implementer(IExportContainerFinder)
     719class ExportContainerFinder(grok.GlobalUtility):
     720    """Finder for local (site-wide) export container.
     721    """
     722
     723    def __call__(self):
     724        """Get the local export container-
     725
     726        If no site can be determined or the site provides no export
     727        container, None is returned.
     728        """
     729        site = grok.getSite()
     730        if site is None:
     731            return None
     732        return site.get('datacenter', None)
  • main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_batching.py

    r9342 r9726  
    2525from zc.async.interfaces import IJob
    2626from zope import schema
    27 from zope.component import provideUtility, getGlobalSiteManager
     27from zope.component import provideUtility, getGlobalSiteManager, getUtility
    2828from zope.component.factory import Factory
    29 from zope.component.hooks import clearSite
     29from zope.component.hooks import clearSite, setSite
    3030from zope.component.interfaces import IFactory
    3131from zope.interface import Interface, implements, verify
     
    3333from waeup.kofa.interfaces import (
    3434    ICSVExporter, IBatchProcessor, IExportJobContainer, IJobManager,
    35     IExportJob)
     35    IExportJob, IExportContainerFinder)
    3636from waeup.kofa.testing import (
    3737    FunctionalLayer, FunctionalTestCase, FakeJob, FakeJobManager)
    3838from waeup.kofa.utils.batching import (
    3939    ExporterBase, BatchProcessor, export_job, AsyncExportJob,
    40     ExportJobContainer)
     40    ExportJobContainer, VirtualExportJobContainer, ExportContainerFinder)
    4141
    4242optionflags = (
     
    396396    # Test ExportJobContainer
    397397
     398    TestedClass = ExportJobContainer
     399
    398400    def setUp(self):
    399401        # register a suitable ICSVExporter as named utility
     
    412414    def test_export_job_interfaces(self):
    413415        # the ExportJobContainer implements promised interfaces correctly...
    414         container = ExportJobContainer()
    415         verify.verifyClass(IExportJobContainer, ExportJobContainer)
     416        container = self.TestedClass()
     417        verify.verifyClass(IExportJobContainer, self.TestedClass)
    416418        verify.verifyObject(IExportJobContainer, container)
    417419        return
     
    419421    def test_start_export_job(self):
    420422        # we can start jobs
    421         container = ExportJobContainer()
     423        container = self.TestedClass()
    422424        container.start_export_job('cave_exporter', 'bob')
    423425        result = self.job_manager._jobs.values()[0]
     
    431433    def test_get_running_export_jobs_all(self):
    432434        # we can get export jobs of all users
    433         container = ExportJobContainer()
     435        container = self.TestedClass()
    434436        container.start_export_job('cave_exporter', 'bob')
    435437        container.start_export_job('cave_exporter', 'alice')
     
    444446    def test_get_running_export_jobs_user(self):
    445447        # we can get the export jobs running for a certain user
    446         container = ExportJobContainer()
     448        container = self.TestedClass()
    447449        container.start_export_job('cave_exporter', 'bob')
    448450        container.start_export_job('cave_exporter', 'alice')
     
    457459    def test_get_running_export_jobs_only_if_exist(self):
    458460        # we get only jobs that are accessible through the job manager...
    459         container = ExportJobContainer()
     461        container = self.TestedClass()
    460462        container.start_export_job('cave_exporter', 'bob')
    461463        container.start_export_job('cave_exporter', 'bob')
     
    473475    def test_get_export_job_status(self):
    474476        # we can get the stati of jobs...
    475         container = ExportJobContainer()
     477        container = self.TestedClass()
    476478        container.start_export_job('cave_exporter', 'alice')
    477479        container.start_export_job('cave_exporter', 'bob')
     
    490492        # we can remove export entries in local lists and the job
    491493        # manager as well...
    492         container = ExportJobContainer()
     494        container = self.TestedClass()
    493495        container.start_export_job('cave_exporter', 'bob')
    494496        entry = container.running_exports[0]
     
    503505    def test_delete_export_entry_remove_file(self):
    504506        # any result files of exports are deleted as well
    505         container = ExportJobContainer()
     507        container = self.TestedClass()
    506508        entry = ('4', 'cave_exporter', 'bob')
    507509        container.running_exports = [entry]
     
    515517    def test_entry_from_job_id(self):
    516518        # we can get an entry for a job_id if the id exists
    517         container = ExportJobContainer()
     519        container = self.TestedClass()
    518520        entry = ('4', 'cave_exporter', 'bob')
    519521        container.running_exports = [entry]
     
    528530        shutil.rmtree(fake_job.dir_path)
    529531        return
     532
     533class VirtualExportJobContainerTests(ExportJobContainerTests):
     534    # VirtualExportJobContainers should provide the
     535    # same functionality as regular ones.
     536
     537    TestedClass = VirtualExportJobContainer
     538
     539    def setUp(self):
     540        super(VirtualExportJobContainerTests, self).setUp()
     541        self.root_job_container = ExportJobContainer()
     542        def fake_finder():
     543            return self.root_job_container
     544        self.gsm = getGlobalSiteManager()
     545        self.gsm.registerUtility(fake_finder, IExportContainerFinder)
     546        return
     547
     548class ExportContainerFinderTests(FunctionalTestCase):
     549    # Tests for export container finder.
     550
     551    layer = FunctionalLayer
     552
     553    def test_get_finder_as_util(self):
     554        # we can get a finder by utility lookup
     555        finder = getUtility(IExportContainerFinder)
     556        self.assertTrue(finder is not None)
     557        self.assertEqual(
     558            IExportContainerFinder.providedBy(finder),
     559            True)
     560        return
     561
     562    def test_iface(self):
     563        # the finder complies with the promised interface
     564        finder = ExportContainerFinder()
     565        verify.verifyClass(IExportContainerFinder,
     566                           ExportContainerFinder)
     567        verify.verifyObject(IExportContainerFinder, finder)
     568        return
     569
     570    def test_no_site(self):
     571        # a finder returns None if no site is available
     572        finder = ExportContainerFinder()
     573        self.assertEqual(
     574            finder(), None)
     575        return
     576
     577    def test_active_site(self):
     578        # we get the datafinder if one is installed and site set
     579        self.getRootFolder()['app'] = University()
     580        finder = getUtility(IExportContainerFinder)
     581        setSite(self.getRootFolder()['app'])
     582        container = finder()
     583        self.assertTrue(container is not None)
     584        return
     585
     586    def test_broken_site(self):
     587        # if the current site has no ExportContainer, we get None
     588        self.getRootFolder()['app'] = University()
     589        app = self.getRootFolder()['app']
     590        del app['datacenter'] # datacenter _is_ the export container
     591        setSite(app)
     592        finder = getUtility(IExportContainerFinder)
     593        container = finder()
     594        self.assertTrue(container is None)
     595        return
Note: See TracChangeset for help on using the changeset viewer.