~launchpad-pqm/launchpad/devel

14557.1.20 by Curtis Hovey
Updated copyright.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.34 by Karl Fogel
Add license header blocks to .py, .zcml, and .pt files that don't have it
2
# GNU Affero General Public License version 3 (see the file LICENSE).
8805.1.6 by Francis J. Lacoste
Extract some helpers to test request publication factories and move the tests for the ShipIt and SSO factories into their own modules.
3
4
"""Helpers for testing out publication related code."""
5
6
__metaclass__ = type
7
__all__ = [
8
    'get_request_and_publication',
9
    'print_request_and_publication',
10762.3.7 by Tim Penhey
Fix the test_traverse function.
10
    'test_traverse',
8805.1.6 by Francis J. Lacoste
Extract some helpers to test request publication factories and move the tests for the ShipIt and SSO factories into their own modules.
11
    ]
12
13
from cStringIO import StringIO
14
15
# Z3 doesn't make this available as a utility.
10762.3.6 by Tim Penhey
More beforePublication bits needed.
16
from zope.app import zapi
8805.1.6 by Francis J. Lacoste
Extract some helpers to test request publication factories and move the tests for the ShipIt and SSO factories into their own modules.
17
from zope.app.publication.requestpublicationregistry import factoryRegistry
11285.1.4 by Michael Hudson
more tests and fixes
18
from zope.app.security.interfaces import IUnauthenticatedPrincipal
10762.3.2 by Tim Penhey
Add a test_traverse method.
19
from zope.component import getUtility
10762.3.6 by Tim Penhey
More beforePublication bits needed.
20
from zope.interface import providedBy
21
from zope.publisher.interfaces.browser import IDefaultSkin
11285.1.4 by Michael Hudson
more tests and fixes
22
from zope.security.management import restoreInteraction
13387.1.7 by Francis J. Lacoste
Make test_traverse sensible for webservice requests.
23
from zope.security.proxy import removeSecurityProxy
10762.3.2 by Tim Penhey
Add a test_traverse method.
24
14600.1.8 by Curtis Hovey
Move c.l.layers to lp.
25
import lp.layers as layers
14600.2.2 by Curtis Hovey
Moved webapp to lp.services.
26
from lp.services.webapp import urlsplit
27
from lp.services.webapp.interaction import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
28
    get_current_principal,
29
    setupInteraction,
30
    )
14600.2.2 by Curtis Hovey
Moved webapp to lp.services.
31
from lp.services.webapp.interfaces import IOpenLaunchBag
32
from lp.services.webapp.servers import ProtocolErrorPublication
8805.1.6 by Francis J. Lacoste
Extract some helpers to test request publication factories and move the tests for the ShipIt and SSO factories into their own modules.
33
34
# Defines an helper function that returns the appropriate
35
# IRequest and IPublication.
36
def get_request_and_publication(host='localhost', port=None,
37
                                method='GET', mime_type='text/html',
38
                                in_stream='', extra_environment=None):
39
    """Helper method that return the IRequest and IPublication for a request.
40
41
    This method emulates what the Zope publisher would do to find the request
42
    and publication class for a particular environment.
43
    """
44
    environment = {'HTTP_HOST': host,
45
                   'REQUEST_METHOD': method,
46
                   'SERVER_PORT': port,
47
                   'CONTENT_TYPE': mime_type}
48
    if extra_environment is not None:
49
        environment.update(extra_environment)
50
    launchpad_factory = factoryRegistry.lookup(
51
        method, mime_type, environment)
52
    request_factory, publication_factory = launchpad_factory()
53
    request = request_factory(StringIO(in_stream), environment)
54
    # Since Launchpad doesn't use ZODB, we use None here.
55
    publication = publication_factory(None)
56
    return request, publication
57
10762.3.2 by Tim Penhey
Add a test_traverse method.
58
8805.1.6 by Francis J. Lacoste
Extract some helpers to test request publication factories and move the tests for the ShipIt and SSO factories into their own modules.
59
def print_request_and_publication(host='localhost', port=None,
60
                                  method='GET',
61
                                  mime_type='text/html',
62
                                  extra_environment=None):
63
    """Helper giving short names for the request and publication."""
64
    request, publication = get_request_and_publication(
65
        host, port, method, mime_type,
66
        extra_environment=extra_environment)
67
    print type(request).__name__.split('.')[-1]
68
    publication_classname = type(publication).__name__.split('.')[-1]
69
    if isinstance(publication, ProtocolErrorPublication):
70
        print "%s: status=%d" % (
71
            publication_classname, publication.status)
72
        for name, value in publication.headers.items():
73
            print "  %s: %s" % (name, value)
74
    else:
75
        print publication_classname
10762.3.2 by Tim Penhey
Add a test_traverse method.
76
77
78
def test_traverse(url):
10762.3.13 by Tim Penhey
Fix the tests for the method renames.
79
    """Traverse the url in the same way normal publishing occurs.
80
81
    Returns a tuple of (object, view, request) where:
82
      object is the last model object in the traversal chain
83
      view is the defined view for the object at the specified url (if
84
        the url didn't directly specify a view, then the view is the
85
        default view for the object.
86
      request is the request object resulting from the traversal.  This
87
        contains a populated traversed_objects list just as a browser
88
        request would from a normal call into the app servers.
89
90
    This call uses the currently logged in user, and does not start a new
91
    transaction.
92
    """
10762.3.2 by Tim Penhey
Add a test_traverse method.
93
    url_parts = urlsplit(url)
94
    server_url = '://'.join(url_parts[0:2])
95
    path_info = url_parts[2]
96
    request, publication = get_request_and_publication(
97
        host=url_parts[1], extra_environment={
98
            'SERVER_URL': server_url,
99
            'PATH_INFO': path_info})
10762.3.6 by Tim Penhey
More beforePublication bits needed.
100
101
    request.setPublication(publication)
102
    # We avoid calling publication.beforePublication because this starts a new
103
    # transaction, which causes an abort of the existing transaction, and the
104
    # removal of any created and uncommitted objects.
105
106
    # Set the default layer.
107
    adapters = zapi.getGlobalSiteManager().adapters
108
    layer = adapters.lookup((providedBy(request),), IDefaultSkin, '')
109
    if layer is not None:
110
        layers.setAdditionalLayer(request, layer)
111
11285.1.6 by Michael Hudson
this seems more likely to work
112
    principal = get_current_principal()
10762.3.6 by Tim Penhey
More beforePublication bits needed.
113
11285.1.4 by Michael Hudson
more tests and fixes
114
    if IUnauthenticatedPrincipal.providedBy(principal):
115
        login = None
116
    else:
117
        login = principal.person
118
    setupInteraction(principal, login, request)
11285.1.3 by Michael Hudson
fix!
119
10762.3.2 by Tim Penhey
Add a test_traverse method.
120
    getUtility(IOpenLaunchBag).clear()
121
    app = publication.getApplication(request)
122
    view = request.traverse(app)
13387.1.7 by Francis J. Lacoste
Make test_traverse sensible for webservice requests.
123
    # Find the object from the view instead on relying that it stays
124
    # in the traversed_objects stack. That doesn't apply to the web
125
    # service for example.
13387.1.23 by Francis J. Lacoste
Handle case where the view didn't store the context
126
    try:
127
        obj = removeSecurityProxy(view).context
128
    except AttributeError:
129
        # But sometime the view didn't store the context...
130
        # Use the last traversed object in these cases.
131
        obj = request.traversed_objects[-2]
11285.1.3 by Michael Hudson
fix!
132
133
    restoreInteraction()
134
10762.3.2 by Tim Penhey
Add a test_traverse method.
135
    return obj, view, request