[Checkins] SVN: Products.QueueCatalog/trunk/ - factor out and
expand queue conflict tests
Jens Vagelpohl
jens at dataflake.org
Mon May 8 10:55:45 EDT 2006
Log message for revision 68024:
- factor out and expand queue conflict tests
- update copyrights
- fix long lines and sone other stylistic improvements
Changed:
U Products.QueueCatalog/trunk/CHANGES.txt
U Products.QueueCatalog/trunk/CatalogEventQueue.py
U Products.QueueCatalog/trunk/CatalogEventQueueSet.py
U Products.QueueCatalog/trunk/Processor.py
U Products.QueueCatalog/trunk/QueueCatalog.py
U Products.QueueCatalog/trunk/__init__.py
A Products.QueueCatalog/trunk/tests/test_CatalogEventQueue.py
U Products.QueueCatalog/trunk/tests/test_CatalogEventQueueSet.py
U Products.QueueCatalog/trunk/tests/test_QueueCatalog.py
-=-
Modified: Products.QueueCatalog/trunk/CHANGES.txt
===================================================================
--- Products.QueueCatalog/trunk/CHANGES.txt 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/CHANGES.txt 2006-05-08 14:55:44 UTC (rev 68024)
@@ -6,8 +6,8 @@
- Updated the tests to run on Zope 2.8+
- - Enabled conflict testing after changing it to use a quick and dirty
- FileStorage, and expanding it a little.
+ - Factored out queue conflict testing after changing it to use a quick
+ and dirty FileStorage, and expanding it a little.
- Removed the security declaration for a method named refreshCatalog
which was added in version 1.0 - this is the wrong place to apply
Modified: Products.QueueCatalog/trunk/CatalogEventQueue.py
===================================================================
--- Products.QueueCatalog/trunk/CatalogEventQueue.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/CatalogEventQueue.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -176,7 +176,6 @@
# transaction previous to the undone transaction.
# Committed is always the currently committed data.
-
oldstate_data = oldstate['_data']
committed_data = committed['_data']
newstate_data = newstate['_data']
@@ -207,8 +206,6 @@
# Check aqainst current value. Either we want a
# different event, in which case we give up, or we
# do nothing.
-
-
current = committed_data.get(uid)
if current is not None:
if current[1] != new[1]:
Modified: Products.QueueCatalog/trunk/CatalogEventQueueSet.py
===================================================================
--- Products.QueueCatalog/trunk/CatalogEventQueueSet.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/CatalogEventQueueSet.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,3 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
""" Classes: CatalogEventQueueSet
$Id$
Modified: Products.QueueCatalog/trunk/Processor.py
===================================================================
--- Products.QueueCatalog/trunk/Processor.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/Processor.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
Modified: Products.QueueCatalog/trunk/QueueCatalog.py
===================================================================
--- Products.QueueCatalog/trunk/QueueCatalog.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/QueueCatalog.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -327,7 +327,9 @@
self._update(uid, REMOVED)
if self._immediate_removal:
- self._process_queue(self._queues[hash(uid) % self._buckets], limit=None)
+ self._process_queue( self._queues[hash(uid) % self._buckets]
+ , limit=None
+ )
security.declareProtected(manage_zcatalog_entries, 'process')
def process(self, max=None):
Modified: Products.QueueCatalog/trunk/__init__.py
===================================================================
--- Products.QueueCatalog/trunk/__init__.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/__init__.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
Added: Products.QueueCatalog/trunk/tests/test_CatalogEventQueue.py
===================================================================
--- Products.QueueCatalog/trunk/tests/test_CatalogEventQueue.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/tests/test_CatalogEventQueue.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -0,0 +1,168 @@
+##############################################################################
+#
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""QueueCatalog tests.
+
+$Id$
+"""
+
+import os
+import shutil
+import tempfile
+import unittest
+
+import Testing
+import transaction
+import Zope2
+Zope2.startup()
+
+from Products.ZCatalog.ZCatalog import ZCatalog
+from Products.QueueCatalog.CatalogEventQueue import CatalogEventQueue
+from Products.QueueCatalog.CatalogEventQueue import ADDED
+from Products.QueueCatalog.CatalogEventQueue import CHANGED
+from Products.QueueCatalog.CatalogEventQueue import CHANGED_ADDED
+from Products.QueueCatalog.CatalogEventQueue import REMOVED
+from Products.QueueCatalog.QueueCatalog import QueueCatalog
+from OFS.Application import Application
+from OFS.Folder import Folder
+from Testing.ZopeTestCase.base import TestCase
+from ZODB.POSException import ConflictError
+
+
+class QueueConflictTests(unittest.TestCase):
+
+ def _insane_update(self, queue, uid, etype):
+ # Queue update method that allows insane state changes, needed
+ # to provoke pathological queue states
+ data = queue._data
+ current = data.get(uid)
+ if current is not None:
+ generation, current = current
+
+ if ((current is ADDED or current is CHANGED_ADDED)
+ and etype is CHANGED):
+ etype = CHANGED_ADDED
+ else:
+ generation = 0
+
+ data[uid] = generation+1, etype
+
+ queue._p_changed = 1
+
+ def openDB(self):
+ from ZODB.FileStorage import FileStorage
+ from ZODB.DB import DB
+ self.dir = tempfile.mkdtemp()
+ self.storage = FileStorage(os.path.join(self.dir, 'testQCConflicts.fs'))
+ self.db = DB(self.storage)
+
+ def setUp(self):
+ self.openDB()
+ queue = CatalogEventQueue()
+
+ tm1 = transaction.TransactionManager()
+ conn1 = self.db.open(transaction_manager=tm1)
+ r1 = conn1.root()
+ r1["queue"] = queue
+ del queue
+ self.queue = r1["queue"]
+ tm1.commit()
+
+ tm2 = transaction.TransactionManager()
+ conn2 = self.db.open(transaction_manager=tm2)
+ r2 = conn2.root()
+ self.queue2 = r2["queue"]
+ ignored = dir(self.queue2) # unghostify
+
+ def tearDown(self):
+ transaction.abort()
+ del self.queue
+ del self.queue2
+ if self.storage is not None:
+ self.storage.close()
+ self.storage.cleanup()
+ shutil.rmtree(self.dir)
+
+ def test_rig(self):
+ # Test the test rig
+ self.assertEqual(self.queue._p_serial, self.queue2._p_serial)
+
+ def test_simpleConflict(self):
+ # Using the first connection, index 10 paths
+ for n in range(10):
+ self.queue.update('/f%i' % n, ADDED)
+ self.queue._p_jar.transaction_manager.commit()
+
+ # After this run, the first connection's queuecatalog has 10
+ # entries, the second has none.
+ self.assertEqual(len(self.queue), 10)
+ self.assertEqual(len(self.queue2), 0)
+
+ # Using the second connection, index the other 10 folders
+ for n in range(10):
+ self.queue2.update('/g%i' % n, ADDED)
+
+ # Now both connections' queuecatalogs have 10 entries each, but
+ # for differrent objects
+ self.assertEqual(len(self.queue), 10)
+ self.assertEqual(len(self.queue2), 10)
+
+ # Now we commit. Conflict resolution on the catalog queue should
+ # kick in because both connections have changes. Since none of the
+ # events collide, we should end up with 20 entries in our catalogs.
+ self.queue2._p_jar.transaction_manager.commit()
+ self.queue._p_jar.sync()
+ self.queue2._p_jar.sync()
+ self.assertEqual(len(self.queue), 20)
+ self.assertEqual(len(self.queue2), 20)
+
+ def test_unresolved_add_after_something(self):
+ # If an event is encountered for an object and we are trying to
+ # commit an ADDED event, a conflict is encountered
+ self._insane_update(self.queue, '/f0', CHANGED)
+ self.queue._p_jar.transaction_manager.commit()
+
+ self._insane_update(self.queue2, '/f0', CHANGED)
+ self.queue2._p_jar.transaction_manager.commit()
+
+ self._insane_update(self.queue, '/f0', CHANGED)
+ self.queue._p_jar.transaction_manager.commit()
+
+ # This commit should now raise a conflict
+ self._insane_update(self.queue2, '/f0', ADDED)
+ self.assertRaises( ConflictError
+ , self.queue2._p_jar.transaction_manager.commit
+ )
+
+ def test_unresolved_new_old_current_all_different(self):
+ # If the events we get from the current, new and old states are
+ # all different, we throw in the towel in the form of a conflict.
+ # This test relies on the fact that no OLD state is de-facto treated
+ # as a state.
+ self._insane_update(self.queue, '/f0', CHANGED)
+ self.queue._p_jar.transaction_manager.commit()
+
+ # This commit should now raise a conflict
+ self._insane_update(self.queue2, '/f0', REMOVED)
+ self.assertRaises( ConflictError
+ , self.queue2._p_jar.transaction_manager.commit
+ )
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(QueueConflictTests),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Property changes on: Products.QueueCatalog/trunk/tests/test_CatalogEventQueue.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Products.QueueCatalog/trunk/tests/test_CatalogEventQueueSet.py
===================================================================
--- Products.QueueCatalog/trunk/tests/test_CatalogEventQueueSet.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/tests/test_CatalogEventQueueSet.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,3 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
from __future__ import generators
import unittest
Modified: Products.QueueCatalog/trunk/tests/test_QueueCatalog.py
===================================================================
--- Products.QueueCatalog/trunk/tests/test_QueueCatalog.py 2006-05-08 14:01:29 UTC (rev 68023)
+++ Products.QueueCatalog/trunk/tests/test_QueueCatalog.py 2006-05-08 14:55:44 UTC (rev 68024)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -16,22 +16,16 @@
$Id$
"""
-import os
-import shutil
-import tempfile
import unittest
import Testing
-import transaction
import Zope2
Zope2.startup()
from Products.ZCatalog.ZCatalog import ZCatalog
from Products.QueueCatalog.QueueCatalog import QueueCatalog
-from OFS.Application import Application
from OFS.Folder import Folder
from Testing.ZopeTestCase.base import TestCase
-from ZODB.POSException import ConflictError
class QueueCatalogTests(TestCase):
@@ -236,7 +230,7 @@
def testImmediateDeletion(self):
app = self.app
- app.test_cat = QueueCatalog(1000) # 1000 buckets. I don't want collisions here.
+ app.test_cat = QueueCatalog(1000) # 1000 buckets to prevent collisions
app.test_cat.id = 'test_cat'
app.test_cat.manage_edit(location='/real_cat',
immediate_indexes=['id'], immediate_removal=1)
@@ -247,131 +241,16 @@
f = getattr(app, f.id)
app.test_cat.catalog_object(f)
self.assertEqual(app.test_cat.manage_size(), 20)
- # "Delete" one. This should be processed immediately (including the add-event)
+ # "Delete" one. This should be processed immediately (including
+ # the add-event)
app.test_cat.uncatalog_object(getattr(app, 'f1').getPhysicalPath())
self.assertEqual(app.test_cat.manage_size(), 19)
del app.test_cat
-class QueueConflictTests(unittest.TestCase):
-
- def openDB(self):
- from ZODB.FileStorage import FileStorage
- from ZODB.DB import DB
- self.dir = tempfile.mkdtemp()
- self.storage = FileStorage(os.path.join(self.dir, 'testQCConflicts.fs'))
- self.db = DB(self.storage)
-
- def setUp(self):
- self.openDB()
- app = Application()
-
- tm1 = transaction.TransactionManager()
- conn1 = self.db.open(transaction_manager=tm1)
- r1 = conn1.root()
- r1["Application"] = app
- del app
- self.app = r1["Application"]
- tm1.commit()
-
- self.app.real_cat = ZCatalog('real_cat')
- self.app.real_cat.addIndex('id', 'FieldIndex')
- self.app.real_cat.addIndex('title', 'FieldIndex')
- self.app.real_cat.addIndex('meta_type', 'FieldIndex')
- self.app.queue_cat = QueueCatalog(3) # 3 buckets
- self.app.queue_cat.id = 'queue_cat'
- self.app.queue_cat.manage_edit(location='/real_cat',
- immediate_indexes=[])
-
- # Create stuff to catalog
- for n in range(10):
- f = Folder()
- f.id = 'f%d' % n
- self.app._setOb(f.id, f)
- g = Folder()
- g.id = 'g%d' % n
- self.app._setOb(g.id, g)
-
- # Make sure everything is committed so the second connection sees it
- tm1.commit()
-
- tm2 = transaction.TransactionManager()
- conn2 = self.db.open(transaction_manager=tm2)
- r2 = conn2.root()
- self.app2 = r2["Application"]
- ignored = dir(self.app2) # unghostify
-
- def tearDown(self):
- transaction.abort()
- del self.app
- if self.storage is not None:
- self.storage.close()
- self.storage.cleanup()
- shutil.rmtree(self.dir)
-
- def test_rig(self):
- # Test the test rig
- self.assertEqual(self.app._p_serial, self.app2._p_serial)
-
- def test_simpleConflict(self):
- # Using the first connection, index 10 folders
- for n in range(10):
- f = getattr(self.app, 'f%d' % n)
- self.app.queue_cat.catalog_object(f)
- self.app._p_jar.transaction_manager.commit()
-
- # After this run, the first connection's queuecatalog has 10
- # entries, the second has none.
- self.assertEqual(self.app.queue_cat.manage_size(), 10)
- self.assertEqual(self.app2.queue_cat.manage_size(), 0)
-
- # Using the second connection, index the other 10 folders
- for n in range(10):
- g = getattr(self.app2, 'g%d' % n)
- self.app2.queue_cat.catalog_object(g)
-
- # Now both connections' queuecatalogs have 10 entries each, but
- # for differrent objects
- self.assertEqual(self.app.queue_cat.manage_size(), 10)
- self.assertEqual(self.app2.queue_cat.manage_size(), 10)
-
- # Now we commit. Conflict resolution on the catalog queue should
- # kick in because both connections have changes. Since none of the
- # events collide, we should end up with 20 entries in our catalogs.
- self.app2._p_jar.transaction_manager.commit()
- self.app._p_jar.sync()
- self.app2._p_jar.sync()
- self.assertEqual(self.app.queue_cat.manage_size(), 20)
- self.assertEqual(self.app2.queue_cat.manage_size(), 20)
-
- def test_unresolved_add_after_delete(self):
- # If a DELETE event is encountered for an object and other events
- # happen afterwards, we have entered the twilight zone and give up.
-
- # Taking one item and cataloging it in the first connection, then
- # uncataloging it. There should be 1 event in the queue left
- # afterwards, for uncataloging the content item (DELETE)
- f0 = getattr(self.app, 'f0')
- self.app.queue_cat.catalog_object(f0)
- self.app._p_jar.transaction_manager.commit()
- self.app.queue_cat.uncatalog_object('/f0')
- self.app._p_jar.transaction_manager.commit()
- self.assertEqual(self.app.queue_cat.manage_size(), 1)
-
- # In the second connection, I will newly catalog the same folder again
- # in order to provoke insane state (ADD after DELETE)
- self.app2.queue_cat.catalog_object(f0)
-
- # This commit should now raise a conflict
- self.assertRaises( ConflictError
- , self.app2._p_jar.transaction_manager.commit
- )
-
-
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(QueueCatalogTests),
- unittest.makeSuite(QueueConflictTests),
))
if __name__ == '__main__':
More information about the Checkins
mailing list