← Back to team overview

launchpad-reviewers team mailing list archive

lp:~mwhudson/launchpad/test_traverse-set-participation-bug-611570 into lp:launchpad/devel

 

Michael Hudson has proposed merging lp:~mwhudson/launchpad/test_traverse-set-participation-bug-611570 into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #611570 lp.testing.publication.test_traverse doesn't set the current participation
  https://bugs.launchpad.net/bugs/611570


Hi,

This branch started out by making test_traverse set up a new interaction for the traversal it performs, so as to make the request that is being traversed 'current'.  Then I wrote some more tests and discovered that, at least in some sense, the docstring's claim that it 'uses the current user' was inaccurate, so I fixed that too.

The key test helper I use is bonkers, but I think that's zope's fault (you can read the implementation of the browser:page in zope.browserpage.metaconfigure to see where I cribbed the insanity from).

Cheers,
mwh
-- 
https://code.launchpad.net/~mwhudson/launchpad/test_traverse-set-participation-bug-611570/+merge/31731
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~mwhudson/launchpad/test_traverse-set-participation-bug-611570 into lp:launchpad/devel.
=== modified file 'lib/lp/testing/publication.py'
--- lib/lp/testing/publication.py	2010-04-28 10:13:00 +0000
+++ lib/lp/testing/publication.py	2010-08-04 10:34:45 +0000
@@ -15,13 +15,17 @@
 # Z3 doesn't make this available as a utility.
 from zope.app import zapi
 from zope.app.publication.requestpublicationregistry import factoryRegistry
+from zope.app.security.interfaces import IUnauthenticatedPrincipal
 from zope.component import getUtility
 from zope.interface import providedBy
 from zope.publisher.interfaces.browser import IDefaultSkin
+from zope.security.management import restoreInteraction
 
 from canonical.launchpad.interfaces.launchpad import IOpenLaunchBag
 import canonical.launchpad.layers as layers
 from canonical.launchpad.webapp import urlsplit
+from canonical.launchpad.webapp.interaction import setupInteraction
+from canonical.launchpad.webapp.publisher import get_current_browser_request
 from canonical.launchpad.webapp.servers import ProtocolErrorPublication
 
 
@@ -103,8 +107,13 @@
     if layer is not None:
         layers.setAdditionalLayer(request, layer)
 
-    principal = publication.getPrincipal(request)
-    request.setPrincipal(principal)
+    principal = get_current_browser_request().principal
+
+    if IUnauthenticatedPrincipal.providedBy(principal):
+        login = None
+    else:
+        login = principal.person
+    setupInteraction(principal, login, request)
 
     getUtility(IOpenLaunchBag).clear()
     app = publication.getApplication(request)
@@ -112,4 +121,7 @@
     # Since the last traversed object is the view, the second last should be
     # the object that the view is on.
     obj = request.traversed_objects[-2]
+
+    restoreInteraction()
+
     return obj, view, request

=== added file 'lib/lp/testing/tests/test_publication.py'
--- lib/lp/testing/tests/test_publication.py	1970-01-01 00:00:00 +0000
+++ lib/lp/testing/tests/test_publication.py	2010-08-04 10:34:45 +0000
@@ -0,0 +1,92 @@
+# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for the helpers in `lp.testing.publication`."""
+
+__metaclass__ = type
+
+from zope.app.pagetemplate.simpleviewclass import simple
+from zope.component import getSiteManager, getUtility
+from zope.interface import Interface
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.security.checker import CheckerPublic, Checker, defineChecker
+
+from canonical.launchpad.interfaces.launchpad import ILaunchpadRoot
+from canonical.launchpad.webapp.interfaces import ILaunchBag
+from canonical.launchpad.webapp.publisher import get_current_browser_request
+from canonical.launchpad.webapp.servers import LaunchpadTestRequest
+from canonical.testing import DatabaseFunctionalLayer
+from lp.testing import ANONYMOUS, login, login_person, TestCaseWithFactory
+from lp.testing.publication import test_traverse
+
+
+class TestTestTraverse(TestCaseWithFactory):
+    # Tests for `test_traverse`
+
+    layer = DatabaseFunctionalLayer
+
+    def registerViewCallable(self, view_callable):
+        """Return a URL traversing to which will call `view_callable`.
+
+        :param view_callable: Will be called with no arguments during
+            traversal.
+        """
+        # This method is completely out of control.  Thanks, Zope.
+        name = '+' + self.factory.getUniqueString()
+        class new_class(simple):
+            def __init__(self, context, request):
+                view_callable()
+        required = {}
+        for n in ('browserDefault', '__call__', 'publishTraverse'):
+            required[n] = CheckerPublic
+        defineChecker(new_class, Checker(required))
+        getSiteManager().registerAdapter(
+            new_class, (ILaunchpadRoot, IDefaultBrowserLayer), Interface, name)
+        self.addCleanup(
+            getSiteManager().unregisterAdapter, new_class, 
+            (ILaunchpadRoot, IDefaultBrowserLayer), Interface, name)
+        return 'https://launchpad.dev/' + name
+
+    def test_traverse_simple(self):
+        # test_traverse called with a product URL returns the product
+        # as the traversed object.
+        login(ANONYMOUS)
+        product = self.factory.makeProduct()
+        context, view, request = test_traverse(
+            'https://launchpad.dev/' + product.name)
+        self.assertEqual(product, context)
+
+    def test_request_is_current_during_traversal(self):
+        # The request that test_traverse creates is current during
+        # traversal in the sense of get_current_browser_request.
+        login(ANONYMOUS)
+        requests = []
+        def record_current_request():
+            requests.append(get_current_browser_request())
+        context, view, request = test_traverse(
+            self.registerViewCallable(record_current_request))
+        self.assertEqual(1, len(requests))
+        self.assertIs(request, requests[0])
+
+    def test_participation_restored(self):
+        # test_traverse restores the interaction (and hence
+        # participation) that was present before it was called.
+        request = LaunchpadTestRequest()
+        login(ANONYMOUS, request)
+        product = self.factory.makeProduct()
+        test_traverse('https://launchpad.dev/' + product.name)
+        self.assertIs(request, get_current_browser_request())
+
+    def test_uses_current_user(self):
+        # test_traverse performs the traversal as the currently logged
+        # in user.
+        person = self.factory.makePerson()
+        login_person(person)
+        users = []
+        def record_user():
+            users.append(getUtility(ILaunchBag).user)
+        context, view, request = test_traverse(
+            self.registerViewCallable(record_user))
+        self.assertEqual(1, len(users))
+        self.assertEqual(person, users[0])
+