Author: kskuhlman
Date: Tue Sep 29 22:59:00 2009
New Revision: 6745
URL: http://trac.turbogears.org/changeset/6745
Log:
Port r6651 to 1.5, plus add module setup & teardown to test_visit, since CP3 is
pedantic about clean exits.
Modified:
branches/1.1/turbogears/identity/tests/test_visit.py
branches/1.5/turbogears/identity/tests/test_visit.py
branches/1.5/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl
branches/1.5/turbogears/visit/api.py
Modified: branches/1.1/turbogears/identity/tests/test_visit.py
==============================================================================
--- branches/1.1/turbogears/identity/tests/test_visit.py (original)
+++ branches/1.1/turbogears/identity/tests/test_visit.py Tue Sep 29
22:59:00 2009
@@ -13,6 +13,12 @@
"""Returns a dict containing cookie information to pass to a server."""
return dict(Cookie=response.headers['Set-Cookie'])
+def setup_module():
+ testutil.start_server()
+
+def teardown_module():
+ testutil.stop_server()
+
class SimpleVisitPlugin(object):
Modified: branches/1.5/turbogears/identity/tests/test_visit.py
==============================================================================
--- branches/1.5/turbogears/identity/tests/test_visit.py (original)
+++ branches/1.5/turbogears/identity/tests/test_visit.py Tue Sep 29
22:59:00 2009
@@ -5,19 +5,36 @@
import cherrypy
+import turbogears.visit.api
from turbogears import config, controllers, expose, startup, testutil, visit
-
+from turbogears.visit.savisit import SqlAlchemyVisitManager
def cookie_header(response):
"""Returns a dict containing cookie information to pass to a server."""
return dict(Cookie=response.headers['Set-Cookie'])
+def setup_module():
+ testutil.start_server()
+
+def teardown_module():
+ testutil.stop_server()
+
+
+class SimpleVisitPlugin(object):
+
+ def record_request(self, visit):
+ cherrypy.request.simple_visit_plugin = visit
+
+ def register(self):
+ visit.enable_visit_plugin(self)
+
+
class VisitRoot(controllers.RootController):
@expose()
def index(self):
- new = visit_key = None
+ new = key = None
cur_visit = visit.current()
if cur_visit:
new = cur_visit.is_new
@@ -25,20 +42,25 @@
visit_on = config.get('tools.visit.on')
return dict(new=new, key=key, visit_on=visit_on)
+ @expose()
+ def visit_plugin(self):
+ vi = cherrypy.request.simple_visit_plugin
+ return dict(key=vi.key, is_new=vi.is_new)
+
class TestVisit(TestCase):
def setUp(self):
testutil.stop_server(tg_only = True)
self._visit_manager = config.get('tools.visit.source', 'sqlalchemy')
- config.update({'tools.visit.manager': 'sqlobject'})
+ config.update({'tools.visit.manager': 'sqlalchemy'})
self._visit_on = config.get('tools.visit.on', False)
- self._visit_source = config.get('tools.visit.source', 'cookie')
config.update({'tools.visit.on': True})
self._visit_timeout = config.get('tools.visit.timeout', 20)
config.update({'tools.visit.timeout': 50})
- self.cookie_name = config.get("tools.visit.cookie.name", 'tg-visit')
+ self._visit_source = config.get('tools.visit.source', 'cookie')
self._visit_key_param = config.get("tools.visit.form.name", 'tg_visit')
+ self.cookie_name = config.get("tools.visit.cookie.name", 'tg-visit')
self.app = testutil.make_app(VisitRoot)
testutil.start_server()
@@ -153,3 +175,49 @@
'%a, %d-%b-%Y %H:%M:%S GMT')[:8] + (0,))
should_expire = time.mktime(time.gmtime()) + int(morsel['max-age'])
assert abs(should_expire - expires) < 3, (should_expire, expires,
should_expire - expires)
+
+ def test_visit_plugin(self):
+ """Visit plugins are registered correctly and called for each
request."""
+ plug = SimpleVisitPlugin()
+ plug.register()
+ response1 = self.app.get('/visit_plugin')
+ key = response1.raw['key']
+ response2 = self.app.get('/visit_plugin')
+ assert key == response2.raw['key']
+ assert not response2.raw['is_new']
+
+class MyVisitManager(SqlAlchemyVisitManager):
+ pass
+
+class TestSetVisitManager(TestCase):
+
+ def setUp(self):
+ testutil.stop_server(tg_only = True)
+ self._visit_manager = config.get('tools.visit.manager', 'sqlalchemy')
+ self._visit_on = config.get('tools.visit.on', False)
+ config.update({'tools.visit.on': True})
+ self._visit_timeout = config.get('tools.visit.timeout', 20)
+ config.update({'tools.visit.timeout': 50})
+
+ def tearDown(self):
+ testutil.stop_server(tg_only = True)
+ config.update({'tools.visit.timeout': self._visit_timeout})
+ config.update({'tools.visit.on': self._visit_on})
+ config.update({'tools.visit.manager': self._visit_manager})
+
+ def test_visit_manager_from_class(self):
+ """Visit manager class is loaded correctly from dotted-path
notation."""
+ config.update({'tools.visit.manager':
'turbogears.identity.tests.test_visit.MyVisitManager'})
+ testutil.start_server()
+ assert isinstance(turbogears.visit.api._manager, MyVisitManager)
+
+ def test_visit_manager_from_plugin(self):
+ """Visit manager class is loaded correctly from entry point plugin."""
+ config.update({'tools.visit.manager': 'sqlalchemy'})
+ testutil.start_server()
+ assert isinstance(turbogears.visit.api._manager,
SqlAlchemyVisitManager)
+
+ def test_visit_manager_faiL_missing(self):
+ """Runtime Exception is raised when no visit manager class is found."""
+ config.update({'tools.visit.manager': 'bogus'})
+ self.assertRaises(RuntimeError, visit.start_extension)
Modified:
branches/1.5/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl
==============================================================================
---
branches/1.5/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl
(original)
+++
branches/1.5/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl
Tue Sep 29 22:59:00 2009
@@ -142,7 +142,7 @@
# Specific path for the cookie
# tools.visit.cookie.path = "/"
-# The name of the VisitManager plugin to use for visitor tracking.
+# The name of the VisitManager class or plugin used for visitor tracking.
tools.visit.manager = "${identity}"
#if $identity == "sqlobject"
Modified: branches/1.5/turbogears/visit/api.py
==============================================================================
--- branches/1.5/turbogears/visit/api.py (original)
+++ branches/1.5/turbogears/visit/api.py Tue Sep 29 22:59:00 2009
@@ -10,6 +10,7 @@
import pkg_resources
from turbogears import config
+from turbogears.util import load_class
log = logging.getLogger("turbogears.visit")
@@ -34,13 +35,22 @@
plugins = pkg_resources.iter_entry_points(
"turbogears.visit.manager", plugin_name)
log.debug("Loading visit manager from plugin: %s", plugin_name)
+ provider_class = None
for entrypoint in plugins:
try:
- plugin = entrypoint.load()
- return plugin(timeout)
- except Exception, e:
+ provider_class = entrypoint.load()
+ break
+ except ImportError, e:
log.error("Error loading visit plugin '%s': %s", entrypoint, e)
- raise RuntimeError("VisitManager plugin missing: %s" % plugin_name)
+
+ if not provider_class and '.' in plugin_name:
+ try:
+ provider_class = load_class(plugin_name)
+ except ImportError, e:
+ log.error("Error loading visit class '%s': %s", plugin_name, e)
+ if not provider_class:
+ raise RuntimeError("VisitManager plugin missing: %s" % plugin_name)
+ return provider_class(timeout)
# Interface for the TurboGears extension