[Zope-CVS] CVS: Products/DBTab/tests - __init__.py:1.1 test.conf:1.1 testDBTab.py:1.1

Shane Hathaway shane@zope.com
Wed, 11 Jun 2003 17:53:59 -0400


Update of /cvs-repository/Products/DBTab/tests
In directory cvs.zope.org:/tmp/cvs-serv28232/tests

Added Files:
	__init__.py test.conf testDBTab.py 
Log Message:
Fixed a race condition on connection close.

The root connection was returned to the pool before the mounted
connections were closed.  If another thread pulled the root connection
out of the pool before the original thread finished closing mounted
connections, when the original thread got control back it closed the
mounted connections even though the new thread was using them.  The
symptom was spurious "Should not load state when connection closed"
errors under high load.

Also began unit tests.



=== Added File Products/DBTab/tests/__init__.py ===
"""DBTab tests package"""


=== Added File Products/DBTab/tests/test.conf ===

# DBTab configuration for testing purposes

[Storage: Main]
type=DemoStorage

[Database: Main]
mount_paths=/


[Storage: Mount1]
type=DemoStorage

[Database: Mount1]
mount_paths=/mount1
container_class=OFS.Folder.Folder


[Storage: Mount2]
type=DemoStorage

[Database: Mount2]
mount_paths=/mount2
container_class=OFS.Folder.Folder




=== Added File Products/DBTab/tests/testDBTab.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 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
#
##############################################################################
"""Tests of DBTab
"""

import os
import sys
import unittest
import Testing
import ZODB
from OFS.Application import Application
from Products.DBTab.DBTab import DBTab
from Products.DBTab.MountedObject import setConfiguration, manage_addMounts

try:
    __file__
except NameError:
    __file__ = os.path.abspath(sys.argv[0])


class DBTabTests (unittest.TestCase):

    def setUp(self):
        conf = DBTab([os.path.join(os.path.dirname(__file__), 'test.conf')])
        setConfiguration(conf)
        self.conf = conf
        db = conf.getDatabase('/')
        self.db = db
        conn = db.open()
        root = conn.root()
        root['Application'] = app = Application()
        self.app = app
        get_transaction().commit()  # Get app._p_jar set
        manage_addMounts(app, ('/mount1', '/mount2'))
        get_transaction().commit()  # Get the mount points ready


    def tearDown(self):
        setConfiguration(None)
        get_transaction().abort()
        self.app._p_jar.close()
        del self.app
        del self.db
        for db in self.conf.opened.values():
            db.close()
        del self.conf


    def testRead(self):
        self.assertEqual(self.app.mount1.id, 'mount1')
        self.assertEqual(self.app.mount2.id, 'mount2')


    def testWrite(self):
        app = self.app
        app.mount1.a1 = '1'
        app.mount2.a2 = '2'
        app.a3 = '3'
        self.assertEqual(app.mount1._p_changed, 1)
        self.assertEqual(app.mount2._p_changed, 1)
        self.assertEqual(app._p_changed, 1)
        get_transaction().commit()
        self.assertEqual(app.mount1._p_changed, 0)
        self.assertEqual(app.mount2._p_changed, 0)
        self.assertEqual(app._p_changed, 0)


    def testRaceOnClose(self):
        # There used to be a race condition in
        # ConnectionPatches.close().  The root connection was returned
        # to the pool before the mounted connections were closed.  If
        # another thread pulled the root connection out of the pool
        # before the original thread finished closing mounted
        # connections, when the original thread got control back it
        # closed the mounted connections even though the new thread
        # was using them.

        # Test by patching to watch for a vulnerable moment.

        from ZODB.DB import DB

        def _closeConnection(self, connection):
            self._real_closeConnection(connection)
            mc = connection._mounted_connections
            if mc is not None:
                for c in mc.values():
                    if c._storage is not None:
                        raise AssertionError, "Connection remained partly open"

        DB._real_closeConnection = DB._closeConnection
        DB._closeConnection = _closeConnection
        try:
            conn = self.db.open()
            conn.root()['Application']['mount1']
            conn.root()['Application']['mount2']
            conn.close()
        finally:
            DB._closeConnection = DB._real_closeConnection
            del DB._real_closeConnection


if __name__ == '__main__':
    unittest.main()