############################################################################## # # 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.1 (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. # ############################################################################## """Browser Publication Tests $Id: test_browserpublication.py 38357 2005-09-07 20:14:34Z srichter $ """ import unittest from zope.app.testing import ztapi from StringIO import StringIO from zope.security.interfaces import ForbiddenAttribute from zope.interface import Interface, implements from zope.publisher.publish import publish from zope.publisher.browser import TestRequest, BrowserView from zope.publisher.interfaces.browser import IBrowserPublisher from zope.proxy import getProxiedObject from zope.security.proxy import Proxy, removeSecurityProxy from zope.security.checker import defineChecker, NamesChecker from zope.app.security.principalregistry import principalRegistry from zope.app.publication.browser import BrowserPublication from zope.app.publication.httpfactory import HTTPPublicationRequestFactory from zope.app.publication.traversers import TestTraverser from zope.app.publication.tests.test_zopepublication \ import BasePublicationTests as BasePublicationTests_ from persistent import Persistent def foo(): "I am an otherwise empty docstring." return 'hello base fans' class DummyPublished(object): implements(IBrowserPublisher) def publishTraverse(self, request, name): if name == 'bruce': return foo raise KeyError(name) def browserDefault(self, request): return self, ['bruce'] class DummyView(DummyPublished, BrowserView): __Security_checker__ = NamesChecker(["browserDefault", "publishTraverse"]) class BasePublicationTests(BasePublicationTests_): def _createRequest(self, path, publication, **kw): request = TestRequest(PATH_INFO=path, **kw) request.setPublication(publication) return request class SimpleObject(object): def __init__(self, v): self.v = v class I1(Interface): pass class mydict(dict): implements(I1) class O1(Persistent): implements(I1) class BrowserDefaultTests(BasePublicationTests): """ test browser default many views lead to a default view """ klass = BrowserPublication def testBaseTagNoBase(self): self._testBaseTags('/somepath/@@view/', '') def testBaseTag1(self): self._testBaseTags('/somepath/@@view', 'http://127.0.0.1/somepath/@@view/bruce') def testBaseTag2(self): self._testBaseTags('/somepath/', 'http://127.0.0.1/somepath/@@view/bruce') def testBaseTag3(self): self._testBaseTags('/somepath', 'http://127.0.0.1/somepath/@@view/bruce') def _testBaseTags(self, url, expected): # Make sure I1 and O1 are visible in the module namespace # so that the classes can be pickled. import transaction pub = BrowserPublication(self.db) ztapi.browserView(I1, 'view', DummyView) ztapi.setDefaultViewName(I1, 'view') ztapi.browserViewProviding(None, TestTraverser, IBrowserPublisher) ob = O1() ## the following is for running the tests standalone principalRegistry.defineDefaultPrincipal( 'tim', 'timbot', 'ai at its best') # now place our object inside the application connection = self.db.open() app = connection.root()['Application'] app.somepath = ob transaction.commit() connection.close() defineChecker(app.__class__, NamesChecker(somepath='xxx')) req = self._createRequest(url, pub) response = req.response publish(req, handle_errors=0) self.assertEqual(response.getBase(), expected) def _createRequest(self, path, publication, **kw): request = TestRequest(PATH_INFO=path, **kw) request.setPublication(publication) return request class BrowserPublicationTests(BasePublicationTests): klass = BrowserPublication def testAdaptedTraverseNameWrapping(self): class Adapter(object): implements(IBrowserPublisher) def __init__(self, context, request): self.context = context self.counter = 0 def publishTraverse(self, request, name): self.counter += 1 return self.context[name] ztapi.browserViewProviding(I1, Adapter, IBrowserPublisher) ob = mydict() ob['bruce'] = SimpleObject('bruce') ob['bruce2'] = SimpleObject('bruce2') pub = self.klass(self.db) ob2 = pub.traverseName(self._createRequest('/bruce', pub), ob, 'bruce') self.assertRaises(ForbiddenAttribute, getattr, ob2, 'v') self.assertEqual(removeSecurityProxy(ob2).v, 'bruce') def testAdaptedTraverseDefaultWrapping(self): # Test default content and make sure that it's wrapped. class Adapter(object): implements(IBrowserPublisher) def __init__(self, context, request): self.context = context def browserDefault(self, request): return (self.context['bruce'], 'dummy') ztapi.browserViewProviding(I1, Adapter, IBrowserPublisher) ob = mydict() ob['bruce'] = SimpleObject('bruce') ob['bruce2'] = SimpleObject('bruce2') pub = self.klass(self.db) ob2, x = pub.getDefaultTraversal(self._createRequest('/bruce',pub), ob) self.assertEqual(x, 'dummy') self.assertRaises(ForbiddenAttribute, getattr, ob2, 'v') self.assertEqual(removeSecurityProxy(ob2).v, 'bruce') def testTraverseName(self): pub = self.klass(self.db) class C(object): x = SimpleObject(1) ob = C() r = self._createRequest('/x',pub) ztapi.browserViewProviding(None, TestTraverser, IBrowserPublisher) ob2 = pub.traverseName(r, ob, 'x') self.assertRaises(ForbiddenAttribute, getattr, ob2, 'v') self.assertEqual(removeSecurityProxy(ob2).v, 1) def testTraverseNameView(self): pub = self.klass(self.db) class I(Interface): pass class C(object): implements(I) ob = C() class V(object): def __init__(self, context, request): pass r = self._createRequest('/@@spam',pub) ztapi.browserView(I, 'spam', V) ob2 = pub.traverseName(r, ob, '@@spam') self.assertEqual(ob2.__class__, V) def testTraverseNameSiteManager(self): pub = self.klass(self.db) class C(object): def getSiteManager(self): return SimpleObject(1) ob = C() r = self._createRequest('/++etc++site',pub) ob2 = pub.traverseName(r, ob, '++etc++site') self.assertRaises(ForbiddenAttribute, getattr, ob2, 'v') self.assertEqual(removeSecurityProxy(ob2).v, 1) def testTraverseNameApplicationControl(self): from zope.app.applicationcontrol.applicationcontrol \ import applicationController, applicationControllerRoot pub = self.klass(self.db) r = self._createRequest('/++etc++process',pub) ac = pub.traverseName(r, applicationControllerRoot, '++etc++process') self.assertEqual(ac, applicationController) r = self._createRequest('/++etc++process',pub) app = r.publication.getApplication(r) self.assertEqual(app, applicationControllerRoot) def testHEADFuxup(self): pub = self.klass(None) class User(object): id = 'bob' # With a normal request, we should get a body: request = TestRequest(StringIO(''), {'PATH_INFO': '/'}) request.setPrincipal(User()) request.response.setResult(u"spam") pub.afterCall(request, None) self.assertEqual(request.response.consumeBody(), 'spam' ) # But with a HEAD request, the body should be empty request = TestRequest(StringIO(''), {'PATH_INFO': '/'}) request.setPrincipal(User()) request.method = 'HEAD' request.response.setResult(u"spam") pub.afterCall(request, None) self.assertEqual(request.response.consumeBody(), '') def testUnicode_NO_HTTP_CHARSET(self): # Test so that a unicode body doesn't cause a UnicodeEncodeError request = TestRequest(StringIO(''), {}) request.response.setResult(u"\u0442\u0435\u0441\u0442") headers = request.response.getHeaders() headers.sort() self.assertEqual( headers, [('Content-Length', '8'), ('Content-Type', 'text/plain;charset=utf-8'), ('X-Content-Type-Warning', 'guessed from content'), ('X-Powered-By', 'Zope (www.zope.org), Python (www.python.org)')]) self.assertEqual( request.response.consumeBody(), '\xd1\x82\xd0\xb5\xd1\x81\xd1\x82') class HTTPPublicationRequestFactoryTests(BasePublicationTests): def setUp(self): super(BasePublicationTests, self).setUp() from zope.app.publication.requestpublicationregistry import \ factoryRegistry from zope.app.publication.requestpublicationfactories \ import SOAPFactory, XMLRPCFactory, HTTPFactory, BrowserFactory factoryRegistry.register('*', '*', 'HTTP', 0, HTTPFactory()) factoryRegistry.register('POST', 'text/xml', 'SOAP', 20, SOAPFactory()) factoryRegistry.register('POST', 'text/xml', 'XMLRPC', 10, XMLRPCFactory()) factoryRegistry.register('GET', '*', 'BROWSER', 10, BrowserFactory()) factoryRegistry.register('POST', '*', 'BROWSER', 10, BrowserFactory()) factoryRegistry.register('HEAD', '*', 'BROWSER', 10, BrowserFactory()) def testGetBackSamePublication(self): factory = HTTPPublicationRequestFactory(db=None) args = (StringIO(''), {}) self.assert_(id(factory(*args).publication) == id(factory(*args).publication)) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(BrowserPublicationTests, 'test'), unittest.makeSuite(BrowserDefaultTests, 'test'), unittest.makeSuite(HTTPPublicationRequestFactoryTests, 'test'), )) if __name__ == '__main__': unittest.TextTestRunner().run(test_suite())