[Checkins] SVN: gocept.selenium/trunk/ Merge branch wosc-zodb-isolation
Wolfgang Schnerring
wosc at wosc.de
Sun Dec 26 09:31:26 EST 2010
Log message for revision 119133:
Merge branch wosc-zodb-isolation
Changed:
U gocept.selenium/trunk/plone.cfg
U gocept.selenium/trunk/plone4.cfg
U gocept.selenium/trunk/src/gocept/selenium/grok/fixtures.py
U gocept.selenium/trunk/src/gocept/selenium/grok/tests.py
U gocept.selenium/trunk/src/gocept/selenium/plone/__init__.py
U gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone3/test_plone3.py
U gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone4/test_plone4.py
U gocept.selenium/trunk/src/gocept/selenium/tests/fixture/configure.zcml
U gocept.selenium/trunk/src/gocept/selenium/tests/fixture/dummy.py
U gocept.selenium/trunk/src/gocept/selenium/tests/isolation.py
U gocept.selenium/trunk/src/gocept/selenium/zope2/__init__.py
U gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope210/test_zope210.py
U gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope212/test_zope212.py
U gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_ztk.py
-=-
Modified: gocept.selenium/trunk/plone.cfg
===================================================================
--- gocept.selenium/trunk/plone.cfg 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/plone.cfg 2010-12-26 14:31:25 UTC (rev 119133)
@@ -15,7 +15,7 @@
[test]
recipe = collective.recipe.z2testrunner
zope2part = instance
-defaults = --ignore_dir=ztk --ignore_dir=zope2 --ignore_dir=static --tests-pattern=plone3
+defaults = --ignore_dir=ztk --ignore_dir=zope2 --ignore_dir=static --ignore_dir=plonetesting --tests-pattern=plone3
packages = ${buildout:package}
[instance]
Modified: gocept.selenium/trunk/plone4.cfg
===================================================================
--- gocept.selenium/trunk/plone4.cfg 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/plone4.cfg 2010-12-26 14:31:25 UTC (rev 119133)
@@ -11,7 +11,7 @@
[test]
recipe = zc.recipe.testrunner
-defaults = ["--ignore_dir=ztk", "--ignore_dir=zope", "--ignore_dir=static", "--tests-pattern=plone4"]
+defaults = ["--ignore_dir=ztk", "--ignore_dir=zope", "--ignore_dir=static", "--ignore_dir=plonetesting", "--tests-pattern=plone4"]
eggs = ${instance:eggs}
[instance]
Modified: gocept.selenium/trunk/src/gocept/selenium/grok/fixtures.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/grok/fixtures.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/grok/fixtures.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -12,6 +12,7 @@
#
##############################################################################
+import gocept.selenium.tests.fixture.dummy
import grok
@@ -25,18 +26,29 @@
return '''<html><body>Hello from grok</body></html>'''
-class Set(grok.View):
- grok.name('set.html')
+class DelegatingView(grok.View):
+ # delegates actual functionality to the common isolation fixture, but lets
+ # us register the views grok-style
+
grok.context(object)
def render(self):
- self.context.foo = 1
- return u'setting done'
+ view = getattr(
+ gocept.selenium.tests.fixture.dummy, self.__class__.__name__)()
+ view.context = self.context
+ return view()
-class Get(grok.View):
+class Set(DelegatingView):
+
+ grok.name('set.html')
+
+
+class Get(DelegatingView):
+
grok.name('get.html')
- grok.context(object)
- def render(self):
- return str(getattr(self.context, 'foo', 0))
+
+class IncrementVolatile(DelegatingView):
+
+ grok.name('inc-volatile.html')
Modified: gocept.selenium/trunk/src/gocept/selenium/grok/tests.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/grok/tests.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/grok/tests.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -44,3 +44,6 @@
gocept.selenium.grok.TestCase):
layer = test_layer
+
+ def getDatabase(self):
+ return self.layer.db
Modified: gocept.selenium/trunk/src/gocept/selenium/plone/__init__.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/plone/__init__.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/plone/__init__.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -19,6 +19,11 @@
class TestCase(gocept.selenium.base.TestCase,
+ gocept.selenium.zope2.SandboxPatch,
Products.PloneTestCase.PloneTestCase.FunctionalTestCase):
layer = gocept.selenium.zope2.Layer(PloneSiteLayer)
+
+ def getRootFolder(self):
+ """forward API-compatibility with zope.app.testing"""
+ return self.app
Modified: gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone3/test_plone3.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone3/test_plone3.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone3/test_plone3.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -24,6 +24,9 @@
class PloneTests(gocept.selenium.tests.isolation.IsolationTests,
gocept.selenium.plone.TestCase):
+ def getDatabase(self):
+ return gocept.selenium.zope2.get_current_db()
+
def test_plone_login(self):
sel = self.selenium
sel.open('/plone')
Modified: gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone4/test_plone4.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone4/test_plone4.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/plone/tests/plone4/test_plone4.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -28,6 +28,9 @@
layer = gocept.selenium.zope2.Layer(PloneSiteLayer, testing.isolationLayer)
+ def getDatabase(self):
+ return gocept.selenium.zope2.get_current_db()
+
def test_plone_login(self):
sel = self.selenium
sel.open('/plone')
Modified: gocept.selenium/trunk/src/gocept/selenium/tests/fixture/configure.zcml
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/tests/fixture/configure.zcml 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/tests/fixture/configure.zcml 2010-12-26 14:31:25 UTC (rev 119133)
@@ -19,6 +19,13 @@
<browser:page
for="*"
+ name="inc-volatile.html"
+ class=".dummy.IncrementVolatile"
+ permission="zope.Public"
+ />
+
+ <browser:page
+ for="*"
name="error.html"
class=".dummy.Error"
permission="zope.Public"
Modified: gocept.selenium/trunk/src/gocept/selenium/tests/fixture/dummy.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/tests/fixture/dummy.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/tests/fixture/dummy.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -34,3 +34,16 @@
def __call__(Self):
raise ValueError()
+
+
+class IncrementVolatile(object):
+
+ def __call__(self):
+ c = zope.security.proxy.removeSecurityProxy(self.context)
+ if hasattr(c, 'aq_base'):
+ c = c.aq_base
+
+ if not hasattr(c, '_v_counter'):
+ c._v_counter = 0
+ c._v_counter += 1
+ return str(c._v_counter)
Modified: gocept.selenium/trunk/src/gocept/selenium/tests/isolation.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/tests/isolation.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/tests/isolation.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -17,6 +17,10 @@
class IsolationTests(object):
+ # test_0_set and test_1_get verify that different test methods are isolated
+ # from each other, i.e. that the underlying DemoStorage stacking is wired
+ # up correctly
+
def test_0_set(self):
global ENSURE_ORDER
self.selenium.open('http://%s/set.html' % self.selenium.server)
@@ -31,3 +35,36 @@
self.selenium.open('http://%s/get.html' % self.selenium.server)
self.selenium.assertNotBodyText('1')
ENSURE_ORDER = False
+
+ # subclasses need to implement getRootFolder() and getDatabase()
+ # for the tests below to work
+
+ def test_each_request_gets_a_separate_zodb_connection(self):
+ self.selenium.open(
+ 'http://%s/inc-volatile.html' % self.selenium.server)
+ self.selenium.assertBodyText('1')
+ # We demonstrate isolation using volatile attributes (which are
+ # guaranteed not to be present on separate connections). But since
+ # there is no guarantee that volatile attributes disappear on
+ # transaction boundaries, we need to prevent re-use of the first
+ # connection -- to avoid trouble like "it's the same connection, so the
+ # volatile attribute is still there".
+ #
+ # The proper way to do this would be two requests that are processing
+ # concurrently, but a) gocept.selenium is not prepared for
+ # multi-threaded requests and b) simulating that would be a major pain,
+ # so we cheat and force the opening of another connection by claiming
+ # one here.
+ db = self.getDatabase()
+ conn = db.open()
+ self.selenium.open(
+ 'http://%s/inc-volatile.html' % self.selenium.server)
+ conn.close()
+ self.selenium.assertBodyText('1')
+
+ def test_requests_get_different_zodb_connection_than_tests(self):
+ root = self.getRootFolder()
+ root._v_counter = 1
+ self.selenium.open(
+ 'http://%s/inc-volatile.html' % self.selenium.server)
+ self.selenium.assertBodyText('1')
Modified: gocept.selenium/trunk/src/gocept/selenium/zope2/__init__.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/zope2/__init__.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/zope2/__init__.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -16,6 +16,7 @@
import Testing.ZopeTestCase
import Testing.ZopeTestCase.threadutils
import Testing.ZopeTestCase.utils
+import Zope2
import gocept.selenium.base
@@ -52,7 +53,49 @@
super(Layer, self).tearDown()
+class SandboxPatch(object):
+ # Testing.ZopeTestCase.sandbox.Sandbox swapping of the DemoStorage is a
+ # little... crude:
+ #
+ # ZApplicationWrapper is instantiated with a DB from
+ # Testing/custom_zodb, which is never used later on, since Sandbox
+ # passes in the connection (to the current DB) to use instead. This
+ # connection is also stored globally in
+ # Testing.ZopeTestCase.sandbox.AppZapper (and passed to requests via
+ # the bobo_traverse monkey-patch there) -- which means that there only
+ # ever is one single ZODB connection, among the test code and the HTTP
+ # requests, and among concurrent requests. This clearly is not what we
+ # want.
+ #
+ # Thus, this rewrite of the upstream method, that properly changes the
+ # DB in ZApplicationWrapper and does *not* use AppZapper, yielding a
+ # new connection upon each traversal. (For reference and since it took
+ # me quite a while to figure out where everything is: this code is
+ # adapted from the original Sandbox._app and the normal Zope2 startup
+ # in Zope2.__init__).
+
+ def _app(self):
+ Zope2.startup()
+ stuff = Zope2.bobo_application._stuff
+ db = Testing.ZopeTestCase.ZopeLite.sandbox()
+ Zope2.bobo_application._stuff = (db,) + stuff[1:]
+ app = Zope2.bobo_application()
+ app = Testing.ZopeTestCase.utils.makerequest(app)
+ Testing.ZopeTestCase.connections.register(app)
+ return app
+
+
+def get_current_db():
+ """helper for gocept.selenium.tests.isolation"""
+ return Zope2.bobo_application._stuff[0]
+
+
class TestCase(gocept.selenium.base.TestCase,
+ SandboxPatch,
Testing.ZopeTestCase.FunctionalTestCase):
layer = Layer(*BASE_LAYERS)
+
+ def getRootFolder(self):
+ """forward API-compatibility with zope.app.testing"""
+ return self.app
Modified: gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope210/test_zope210.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope210/test_zope210.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope210/test_zope210.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -12,18 +12,20 @@
#
##############################################################################
+import Testing.ZopeTestCase
+import gocept.selenium.tests.isolation
+import gocept.selenium.zope2
import unittest
-import gocept.selenium.zope2
-import gocept.selenium.tests.isolation
-import Testing.ZopeTestCase
Testing.ZopeTestCase.installProduct('Five')
class Zope2Tests(gocept.selenium.tests.isolation.IsolationTests,
gocept.selenium.zope2.TestCase):
- pass
+ def getDatabase(self):
+ return gocept.selenium.zope2.get_current_db()
+
def test_suite():
return unittest.makeSuite(Zope2Tests)
Modified: gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope212/test_zope212.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope212/test_zope212.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/zope2/tests/zope212/test_zope212.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -12,12 +12,12 @@
#
##############################################################################
-import unittest
-import gocept.selenium.zope2
+from gocept.selenium.zope2 import BASE_LAYERS
from gocept.selenium.zope2 import testing
-from gocept.selenium.zope2 import BASE_LAYERS
+import Testing.ZopeTestCase
import gocept.selenium.tests.isolation
-import Testing.ZopeTestCase
+import gocept.selenium.zope2
+import unittest
Testing.ZopeTestCase.installProduct('Five')
@@ -27,6 +27,9 @@
layer = gocept.selenium.zope2.Layer(testing.isolationLayer, *BASE_LAYERS)
+ def getDatabase(self):
+ return gocept.selenium.zope2.get_current_db()
+
def test_suite():
return unittest.makeSuite(Zope212Tests)
Modified: gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_ztk.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_ztk.py 2010-12-26 14:30:03 UTC (rev 119132)
+++ gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_ztk.py 2010-12-26 14:31:25 UTC (rev 119133)
@@ -12,12 +12,16 @@
#
##############################################################################
+import gocept.selenium.tests.isolation
import gocept.selenium.ztk.testing
-import gocept.selenium.tests.isolation
+import zope.app.testing.functional
class ZTKTests(gocept.selenium.tests.isolation.IsolationTests,
gocept.selenium.ztk.testing.TestCase):
+ def getDatabase(self):
+ return zope.app.testing.functional.FunctionalTestSetup().db
+
def test_selenium_http_500_handling(self):
self.selenium.open('http://%s/error.html' % self.selenium.server)
More information about the checkins
mailing list