[z3-checkins] r18249 - in z3/sqlos/branch/jinty-3.0-fix_the_tests: . transaction

jinty at codespeak.net jinty at codespeak.net
Fri Oct 7 10:02:52 CEST 2005


Author: jinty
Date: Fri Oct  7 10:02:49 2005
New Revision: 18249

Modified:
   z3/sqlos/branch/jinty-3.0-fix_the_tests/adapter.py
   z3/sqlos/branch/jinty-3.0-fix_the_tests/connection.py
   z3/sqlos/branch/jinty-3.0-fix_the_tests/transaction/__init__.py
Log:
Rather than joining only the first transaction, join as objects become dirty.
This is paricularly tricky because the ZopeDatabaseAdapter (ZDA) joins when it
sees a SQL activity.

Sometimes we generate SQL activity only in the prepare phase of a transaction
causing the ZDA to try and join the transaction then. This fails.

The implemented solution is to force the ZDA to join when we join, which is a
little hackish (the interfaces state specifically that we should not be calling
this method).

Some other solutions would be:
    * change the ZDA code to join every transaction
    * change the transaction code to allow joins during the prepare phase

Also update to a non-depreciated version of the transaction interface.

(130:135)


Modified: z3/sqlos/branch/jinty-3.0-fix_the_tests/adapter.py
==============================================================================
--- z3/sqlos/branch/jinty-3.0-fix_the_tests/adapter.py	(original)
+++ z3/sqlos/branch/jinty-3.0-fix_the_tests/adapter.py	Fri Oct  7 10:02:49 2005
@@ -12,8 +12,6 @@
 
 __metaclass__ = type
 
-from transaction import get_transaction
-
 from sqlobject.dbconnection import DBAPI
 from sqlobject import _mysql, _postgres, _sybase, _sqlite
 from sqlos.interfaces import ISQLObject
@@ -46,7 +44,6 @@
         self.debug = 0
         self.supportTransactions = False
         self._dm = SQLObjectTransactionManager(connection)
-        get_transaction().join(self._dm)
 
     def makeConnection(self):
         return self._connection

Modified: z3/sqlos/branch/jinty-3.0-fix_the_tests/connection.py
==============================================================================
--- z3/sqlos/branch/jinty-3.0-fix_the_tests/connection.py	(original)
+++ z3/sqlos/branch/jinty-3.0-fix_the_tests/connection.py	Fri Oct  7 10:02:49 2005
@@ -11,7 +11,6 @@
 """
 __metaclass__ = type
 
-from transaction import get_transaction
 from zope.interface import implements
 from zope.component import ComponentLookupError
 from zope.app import zapi

Modified: z3/sqlos/branch/jinty-3.0-fix_the_tests/transaction/__init__.py
==============================================================================
--- z3/sqlos/branch/jinty-3.0-fix_the_tests/transaction/__init__.py	(original)
+++ z3/sqlos/branch/jinty-3.0-fix_the_tests/transaction/__init__.py	Fri Oct  7 10:02:49 2005
@@ -15,7 +15,7 @@
 
 # The next import is needed so we don't shadow
 # the global 'transaction' module from zope3.
-from transaction import get_transaction
+from transaction import get
 
 from transaction.interfaces import IDataManager, IRollback
 from transaction.util import NoSavepointSupportRollback
@@ -45,7 +45,7 @@
     >>> import tempfile
     >>> import urllib
     >>> fh, testdb_file = tempfile.mkstemp()
-    >>> testdb_url = 'sqlite://' + urllib.pathname2url(testdb_file)
+    >>> testdb_dbi = 'dbi://' + urllib.pathname2url(testdb_file)
 
     First, register the subscribers:
 
@@ -63,15 +63,19 @@
 
     Then, create a connection:
 
-    >>> from sqlobject.dbconnection import connectionForURI
-    >>> from sqlos.tests.sampleperson import SamplePerson
+    >>> import sqlite
     >>> from sqlos.adapter import SQLiteAdapter
-    >>> connection = connectionForURI(testdb_url)
-    >>> adapter = SQLiteAdapter(connection.makeConnection())
+    >>> from zope.app.rdb import ZopeDatabaseAdapter
+    >>> class SQLiteda(ZopeDatabaseAdapter):
+    ...     def _connection_factory(self):
+    ...         return sqlite.connect(testdb_file)
+    >>> zda = SQLiteda(testdb_dbi)
+    >>> adapter = SQLiteAdapter(zda())
 
     Stuff the connection into the test class and initialize the table
     if it doesn't exists yet:
 
+    >>> from sqlos.tests.sampleperson import SamplePerson
     >>> SamplePerson._connection = adapter
     >>> SamplePerson.createTable(ifNotExists=True)
 
@@ -125,7 +129,7 @@
     False
     >>> person._expire_called
     False
-    
+
     Prepare the transaction, make sure we get the expected values:
 
     >>> t1 = '1'
@@ -191,12 +195,47 @@
     >>> person.dirty, person._expired
     (False, False)
 
+    Lets abort the current transaction to cleanup:
+
+    >>> from transaction import get
+    >>> get().abort()
+
+    Now lets test the integration with the zope transaction machinery, to make
+    sure that the Zope DA is registered for committing and that our transaction
+    manager is also called:
+
+    >>> oldcommit = SQLObjectTransactionManager.commit
+    >>> def commit(self, txn):
+    ...     print 'committing'
+    ...     oldcommit(self, txn)
+    >>> SQLObjectTransactionManager.commit = commit
+    >>> from zope.app.rdb import ZopeConnection
+    >>> oldregister = ZopeConnection.registerForTxn
+    >>> def register(self):
+    ...     if not self._txn_registered:
+    ...         print 'registering zope da for txn'
+    ...     oldregister(self)
+    >>> ZopeConnection.registerForTxn = register
+
+    change the sample person and try another commit
+    (regression test for http://codespeak.net/issues/z3/issue9):
+
+    >>> people = list(SamplePerson.select(SamplePerson.q.username=='sidnei'))
+    registering zope da for txn
+    >>> assert len(people) == 1
+    >>> people[0].username = 'alan'
+    >>> from transaction import get
+    >>> get().commit()
+    committing
+
     And then cleanup the monkeypatched method:
 
     >>> SamplePerson.syncUpdate = oldsync
     >>> del SamplePerson._sync_called
     >>> SamplePerson.expire = oldexpire
     >>> del SamplePerson._expire_called
+    >>> SQLObjectTransactionManager.commit = oldcommit
+    >>> ZopeConnection.registerForTxn = oldregister
 
     And finally call tearDown and cleanup:
 
@@ -212,6 +251,7 @@
         self.sqlconnection = sqlconnection
         self.state = 0
         self.prepared = False
+        self._joined_txn = False
         self.delta = 0
         self.transaction = None
 
@@ -246,8 +286,9 @@
         self.delta = 0
         for obj in self.objects:
             expired(obj)
-        self.sqlconnection.rollback()
+        self.sqlconnection.rollback()# Doesn't the Zope DA take care of this?
         self.objects.clear()
+        self._joined_txn = False
 
     def commit(self, txn):
         if not self.prepared:
@@ -261,8 +302,9 @@
             # XXX Can't know if modified has been fired yet. Maybe we
             # should *not* fire a modified event here?
             modified(obj)
-        self.sqlconnection.commit()
+        self.sqlconnection.commit() # Doesn't the Zope DA take care of this?
         self.objects.clear()
+        self._joined_txn = False
 
     def register(self, obj):
         if not ISQLObject.providedBy(obj):
@@ -271,6 +313,13 @@
                                "manager")
         self.objects.add(obj)
         self.delta += 1
+        if not self._joined_txn:
+            # register the Zope DA connection as well, becuse when we prepare,
+            # and cause DB activity, it might try to register as well. which
+            # fails. not very nice at all.
+            self.sqlconnection.registerForTxn()
+            get().join(self)
+            self._joined_txn = True
 
     def savepoint(self, txn):
         """Create a savepoint that can not be rolled back"""


More information about the z3-checkins mailing list