[z3-checkins] r18261 - in z3/sqlos/trunk: . auth event ftests interfaces testing tests transaction

andres at codespeak.net andres at codespeak.net
Fri Oct 7 15:17:30 CEST 2005


Author: andres
Date: Fri Oct  7 15:17:26 2005
New Revision: 18261

Added:
   z3/sqlos/trunk/testing/
      - copied from r18260, z3/sqlos/branch/jinty-3.0-fix_the_tests/testing/
   z3/sqlos/trunk/testing/__init__.py
      - copied unchanged from r18260, z3/sqlos/branch/jinty-3.0-fix_the_tests/testing/__init__.py
   z3/sqlos/trunk/testing/sampleperson.py
      - copied unchanged from r18260, z3/sqlos/branch/jinty-3.0-fix_the_tests/testing/sampleperson.py
   z3/sqlos/trunk/testing/testdb.py
      - copied unchanged from r18260, z3/sqlos/branch/jinty-3.0-fix_the_tests/testing/testdb.py
Removed:
   z3/sqlos/trunk/tests/sampleperson.py
Modified:
   z3/sqlos/trunk/_sqlos.py
   z3/sqlos/trunk/auth/__init__.py
   z3/sqlos/trunk/configure.zcml
   z3/sqlos/trunk/connection.py
   z3/sqlos/trunk/event/configure.zcml
   z3/sqlos/trunk/event/subscriber.py
   z3/sqlos/trunk/ftests/test_transaction.py
   z3/sqlos/trunk/interfaces/__init__.py
   z3/sqlos/trunk/transaction/__init__.py
Log:
-Merged trunk and the jinty-3.0-fix_the_tests branch. -fixed some warnings.
-Made zope 3.1 compatible


Modified: z3/sqlos/trunk/_sqlos.py
==============================================================================
--- z3/sqlos/trunk/_sqlos.py	(original)
+++ z3/sqlos/trunk/_sqlos.py	Fri Oct  7 15:17:26 2005
@@ -29,11 +29,13 @@
     def _set_dirty(self, value):
         if value:
             self._connection._dm.register(self)
-        else:
-            # XXX: 'objects' shouldn't really be fiddled directly like this.
-            # Probably there should be an unregister function.
-            #   - Andrew Bennetts, 2005-01-05
-            self._connection._dm.objects.discard(self)
+        # This breaks the transaction functional tests and seems to be an 
+        # optimization only. So I've commented it out. - jinty 2005-10-5
+        #else:
+        #    # XXX: 'objects' shouldn't really be fiddled directly like this.
+        #    # Probably there should be an unregister function.
+        #    #   - Andrew Bennetts, 2005-01-05
+        #    self._connection._dm.objects.discard(self)
         self._dirty = value
 
     def _get_dirty(self):

Modified: z3/sqlos/trunk/auth/__init__.py
==============================================================================
--- z3/sqlos/trunk/auth/__init__.py	(original)
+++ z3/sqlos/trunk/auth/__init__.py	Fri Oct  7 15:17:26 2005
@@ -16,7 +16,6 @@
 from zope.app import zapi
 from zope.app.pluggableauth.interfaces import ILoginPasswordPrincipalSource
 from zope.app.pluggableauth import SimplePrincipal
-from zope.exceptions import NotFoundError
 
 from sqlos.container import SQLObjectContainer
 from sqlos.interfaces.auth import ISQLObjectPrincipalSource
@@ -51,7 +50,7 @@
         for p in self.readPrincipals():
             if p.id == id:
                 return p
-        raise NotFoundError, id
+        raise StandardError, id
 
     def getPrincipals(self, name):
         """See IPrincipalSource."""

Modified: z3/sqlos/trunk/configure.zcml
==============================================================================
--- z3/sqlos/trunk/configure.zcml	(original)
+++ z3/sqlos/trunk/configure.zcml	Fri Oct  7 15:17:26 2005
@@ -136,7 +136,6 @@
     For now, you need to change the factory here if you want
     to use a diferent connection type.
     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-  -->
 
   <adapter
       provides=".interfaces.IZopeSQLConnection"
@@ -144,6 +143,7 @@
       permission="zope.Public"
       factory=".adapter.PostgresAdapter"
       />
+  -->
 
   <adapter
       provides="zope.app.container.interfaces.INameChooser"

Modified: z3/sqlos/trunk/connection.py
==============================================================================
--- z3/sqlos/trunk/connection.py	(original)
+++ z3/sqlos/trunk/connection.py	Fri Oct  7 15:17:26 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
@@ -90,7 +89,12 @@
                 warnings.warn("Couldn't find a rdb connection by the "
                               "name %s. Please verify your setup." % name,
                               SQLObjectWarning, 3)
-            connCache[key] = IZopeSQLConnection(newconn()).transaction()
+            conn = IZopeSQLConnection(newconn())
+            if conn.supportTransactions:
+                connCache[key] = conn.transaction()
+            else: # At least MySQL does not support transactions
+                connCache[key] = conn
+
         return connCache[key]
 
     def releaseConnection(name):

Modified: z3/sqlos/trunk/event/configure.zcml
==============================================================================
--- z3/sqlos/trunk/event/configure.zcml	(original)
+++ z3/sqlos/trunk/event/configure.zcml	Fri Oct  7 15:17:26 2005
@@ -1,18 +1,18 @@
 <configure xmlns="http://namespaces.zope.org/zope">
 
   <subscriber
-      factory=".subscriber.sqlobjectModifiedSubscriber"
+      handler=".subscriber.sqlobjectModifiedSubscriber"
       for="zope.app.event.interfaces.IObjectModifiedEvent"
       />
 
   <subscriber
-      factory=".subscriber.sqlobjectCreatedSubscriber"
+      handler=".subscriber.sqlobjectCreatedSubscriber"
       for="zope.app.event.interfaces.IObjectCreatedEvent"
       />
 
   <subscriber
-      factory=".subscriber.sqlobjectExpiredSubscriber"
+      handler=".subscriber.sqlobjectExpiredSubscriber"
       for="sqlos.event.interfaces.IObjectExpiredEvent"
       />
 
-</configure>
\ No newline at end of file
+</configure>

Modified: z3/sqlos/trunk/event/subscriber.py
==============================================================================
--- z3/sqlos/trunk/event/subscriber.py	(original)
+++ z3/sqlos/trunk/event/subscriber.py	Fri Oct  7 15:17:26 2005
@@ -31,7 +31,7 @@
 
 def sqlobjectExpiredSubscriber(event):
     obj = event.object
-
+    
     if not ISQLObject.providedBy(obj): return
 
     from sqlos.connection import connCache

Modified: z3/sqlos/trunk/ftests/test_transaction.py
==============================================================================
--- z3/sqlos/trunk/ftests/test_transaction.py	(original)
+++ z3/sqlos/trunk/ftests/test_transaction.py	Fri Oct  7 15:17:26 2005
@@ -10,57 +10,41 @@
 $Id$
 """
 import unittest
-from transaction import get_transaction
+from transaction import get
 
-from zope.app.tests.functional import BrowserTestCase
-from zope.app import zapi
-from zope.app.tests import setup
+from zope.app.testing.functional import BrowserTestCase
+from zope.app.testing import ztapi, setup
 from zope.app.rdb import ZopeConnection
 from zope.app.rdb.interfaces import IZopeDatabaseAdapter
 from zope.security.checker import defineChecker, NoProxy
 
 from sqlos import getFactory
 from sqlos.container import SQLObjectContainer
-from sqlos.tests.sampleperson import SamplePerson
+from sqlos.testing.sampleperson import SamplePerson, SamplePersonContainer
 
 from psycopgda.adapter import PsycopgAdapter
 
 __metaclass__ = type
 
-DSN = 'dbi://zope3:123@localhost:5432/zope3'
-
-defineChecker(SamplePerson, NoProxy)
-
 class TestTransaction(BrowserTestCase):
 
     def setUp(self):
-        BrowserTestCase.setUp(self)
-        self.conn = PsycopgAdapter(DSN)
-        utilities = zapi.getService(None, zapi.servicenames.Utilities)
-        utilities.provideUtility(IZopeDatabaseAdapter, self.conn, 'stub')
-        container = SQLObjectContainer()
-        container = self.createContainer(container)
-
-        # Create a service manager at the approot level
-        mgr = setup.createServiceManager(container)
-
-        container.classNames = ['SamplePerson',]
-        kwargs = {'fullname':'Sidnei da Silva',
-                'username':'sidnei',
-                'password':'test'}
-        self.person = self.createObject(container, **kwargs)
-        get_transaction().commit()
-
-    def createContainer(self, container):
-        folder = self.getRootFolder()
-        folder['sqlcontainer'] = container
-        return folder['sqlcontainer']
-
-    def createObject(self, container, **kwargs):
-        factory = getFactory(container.classNames[0])
-        person = factory.new(**kwargs)
-        container['sampleperson'] =  person
-        return container['SamplePerson.%s' % person.id]
+        super(TestTransaction, self).setUp()
+        root = self.getRootFolder()
+        sqlcontainer = SQLObjectContainer()
+        root['sqlcontainer'] = sqlcontainer
+        # get the factory for the container, create the person and add them
+        #factory = sqlcontainer.allowedFactories()[0]
+        SamplePerson.createTable(ifNotExists=True)
+        self.person = SamplePerson(fullname='Sidnei da Silva',
+                                   username='sidnei',
+                                   password='test')
+        sqlcontainer['SamplePerson.%s' % self.person.id] = self.person
+        # Commit what we have done
+        get().commit()
+
+    def supportTransactions(self):
+        return SamplePerson._connection.supportTransactions
 
     def testChange(self):
         person = self.person
@@ -70,11 +54,14 @@
         person.fullname = 'Sidnei Silva'
         person.username = 'dreamcatcher'
         person.password = 'pass'
+        person.syncUpdate() # XXX - This sync should not be necessary but is
+                            # unless _cacheValues=False is removed from
+                            # SamplePerson - jinty
         self.assertEqual(person.fullname, 'Sidnei Silva')
         self.assertEqual(person.username, 'dreamcatcher')
         self.assertEqual(person.password, 'pass')
-
-    def testAbort(self):
+    
+    def testCommit(self):
         person = self.person
         self.assertEqual(person.fullname, 'Sidnei da Silva')
         self.assertEqual(person.username, 'sidnei')
@@ -82,19 +69,40 @@
         person.fullname = 'Sidnei Silva'
         person.username = 'dreamcatcher'
         person.password = 'pass'
-        get_transaction().abort()
+        get().commit()
+        person.syncUpdate() # Let's see what is in the database
+        self.assertEqual(person.fullname, 'Sidnei Silva')
+        self.assertEqual(person.username, 'dreamcatcher')
+        self.assertEqual(person.password, 'pass')
+
+    def testAbort(self):
+        person = self.person
         self.assertEqual(person.fullname, 'Sidnei da Silva')
         self.assertEqual(person.username, 'sidnei')
         self.assertEqual(person.password, 'test')
+        person.fullname = 'Sidnei Silva'
+        person.username = 'dreamcatcher'
+        person.password = 'pass'
+        person.sync() # Sunc to make sure that the DB is sent the statements
+        get().abort()
+        if self.supportTransactions():
+            self.assertEqual(person.fullname, 'Sidnei da Silva')
+            self.assertEqual(person.username, 'sidnei')
+            self.assertEqual(person.password, 'test')
+        else:
+            # ya well no fine
+            self.assertEqual(person.fullname, 'Sidnei Silva')
+            self.assertEqual(person.username, 'dreamcatcher')
+            self.assertEqual(person.password, 'pass')
 
     def tearDown(self):
         self.person.destroySelf()
-        BrowserTestCase.tearDown(self)
+        super(TestTransaction, self).tearDown()
+        SamplePerson.dropTable()
 
 def test_suite():
     suite = unittest.TestSuite()
-    # XXX disable for now, this is too broken
-    # suite.addTest(unittest.makeSuite(TestTransaction))
+    suite.addTest(unittest.makeSuite(TestTransaction))
     return suite
 
 

Modified: z3/sqlos/trunk/interfaces/__init__.py
==============================================================================
--- z3/sqlos/trunk/interfaces/__init__.py	(original)
+++ z3/sqlos/trunk/interfaces/__init__.py	Fri Oct  7 15:17:26 2005
@@ -62,7 +62,7 @@
     def transaction():
         """ Return a transaction object for this connection """
 
-    def queryInsertID(table, idName, id, names, values):
+    def queryInsertID(soInstance, id, names, values):
         """ Insert a row into the database and return the generated id """
 
     def iterSelect(select):

Deleted: /z3/sqlos/trunk/tests/sampleperson.py
==============================================================================
--- /z3/sqlos/trunk/tests/sampleperson.py	Fri Oct  7 15:17:26 2005
+++ (empty file)
@@ -1,28 +0,0 @@
-from zope.interface import implements
-from sqlobject import *
-from sqlos import SQLOS
-from sqlos.interfaces import ISQLSchema
-from zope.schema import TextLine, Text, Datetime
-
-class IPerson(ISQLSchema):
-
-    fullname = TextLine(title=u'Full Name',
-                    description=u"The full name of the user")
-    username = TextLine(title=u'Username',
-                    description=u"The user's login")
-    password = TextLine(title=u'Password',
-                    description=u"The user's password")
-
-class SamplePerson(SQLOS):
-
-    implements(IPerson)
-
-    # Disable cache, so we can see the real contents of the database
-    # during testing.
-    _cacheValues = False
-
-    _columns = [
-        StringCol('fullname', length=50, notNull=1),
-        StringCol('username', length=20, notNull=1),
-        StringCol('password', length=20, notNull=1),
-        ]

Modified: z3/sqlos/trunk/transaction/__init__.py
==============================================================================
--- z3/sqlos/trunk/transaction/__init__.py	(original)
+++ z3/sqlos/trunk/transaction/__init__.py	Fri Oct  7 15:17:26 2005
@@ -15,10 +15,9 @@
 
 # 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
+from transaction.interfaces import IDataManager
 from zope.interface import implements
 from zope.app.event.objectevent import modified
 from sqlos.interfaces import ISQLObject
@@ -54,19 +53,25 @@
     >>> ztapi.handle([IObjectCreatedEvent], sqlobjectCreatedSubscriber)
     >>> ztapi.handle([IObjectModifiedEvent], sqlobjectModifiedSubscriber)
 
+    Make a testing db:
+
+    >>> from sqlos.testing import TestDB
+    >>> testdb = TestDB()
+
     Then, create a connection:
 
-    >>> from sqlobject.dbconnection import connectionForURI
-    >>> from sqlos.tests.sampleperson import SamplePerson
-    >>> from sqlos.adapter import SQLiteAdapter
-    >>> connection = connectionForURI('sqlite:///tmp/sqlite.db')
-    >>> adapter = SQLiteAdapter(connection.makeConnection())
+    >>> adapter = testdb.connectionAdapterFactory()
 
     Stuff the connection into the test class and initialize the table
     if it doesn't exists yet:
 
-    >>> SamplePerson._connection = adapter
-    >>> SamplePerson.createTable(ifNotExists=True)
+    >>> from sqlos.testing.sampleperson import SamplePerson
+    >>> oldconn = SamplePerson._connection
+    >>> if adapter.supportTransactions == True:
+    ...     SamplePerson._connection = adapter.transaction()
+    ... else:
+    ...     SamplePerson._connection = adapter
+    >>> SamplePerson.createTable()
 
     Now create a SamplePerson for testing:
 
@@ -112,6 +117,13 @@
     >>> dm.state, dm.delta
     (0, 2)
 
+    Check that syncUpdate() hasn't been called yet:
+
+    >>> person._sync_called
+    False
+    >>> person._expire_called
+    False
+
     Prepare the transaction, make sure we get the expected values:
 
     >>> t1 = '1'
@@ -127,10 +139,11 @@
     ...
     TypeError: Already prepared
 
-    Check that syncUpdate() hasn't been called yet:
+    Check that syncUpdate() has been called, but not expire:
+    XXX I am not sure why syncUpdate is called rather than just sync????
 
     >>> person._sync_called
-    False
+    True
     >>> person._expire_called
     False
 
@@ -176,15 +189,52 @@
     >>> 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
+    >>> SamplePerson._connection = oldconn
 
-    And finally call tearDown to cleanup the environment:
+    And finally call tearDown and cleanup:
 
+    >>> testdb.tearDown()
     >>> tearDown()
     """
 
@@ -195,6 +245,7 @@
         self.sqlconnection = sqlconnection
         self.state = 0
         self.prepared = False
+        self._joined_txn = False
         self.delta = 0
         self.transaction = None
 
@@ -229,8 +280,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:
@@ -244,8 +296,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):
@@ -254,14 +307,14 @@
                                "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"""
-        if self.prepared:
-            raise TypeError("Can't get savepoint during two-phase commit")
-        self._checkTransaction(txn)
-        self.transaction = txn
-        return NoSavepointSupportRollback(self)
 
     def sortKey(self):
         return str(id(self))


More information about the z3-checkins mailing list