%PDF- %PDF-
Direktori : /lib/python3/dist-packages/twisted/web/test/ |
Current File : //lib/python3/dist-packages/twisted/web/test/test_resource.py |
# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Tests for L{twisted.web.resource}. """ from twisted.trial.unittest import TestCase from twisted.web.error import UnsupportedMethod from twisted.web.http_headers import Headers from twisted.web.iweb import IRequest from twisted.web.resource import ( FORBIDDEN, NOT_FOUND, Resource, _UnsafeErrorPage as ErrorPage, _UnsafeForbiddenResource as ForbiddenResource, _UnsafeNoResource as NoResource, getChildForRequest, ) from twisted.web.test.requesthelper import DummyRequest class ErrorPageTests(TestCase): """ Tests for L{_UnafeErrorPage}, L{_UnsafeNoResource}, and L{_UnsafeForbiddenResource}. """ errorPage = ErrorPage noResource = NoResource forbiddenResource = ForbiddenResource def test_deprecatedErrorPage(self) -> None: """ The public C{twisted.web.resource.ErrorPage} alias for the corresponding C{_Unsafe} class produces a deprecation warning when imported. """ from twisted.web.resource import ErrorPage self.assertIs(ErrorPage, self.errorPage) [warning] = self.flushWarnings() self.assertEqual(warning["category"], DeprecationWarning) self.assertIn("twisted.web.pages.errorPage", warning["message"]) def test_deprecatedNoResource(self) -> None: """ The public C{twisted.web.resource.NoResource} alias for the corresponding C{_Unsafe} class produces a deprecation warning when imported. """ from twisted.web.resource import NoResource self.assertIs(NoResource, self.noResource) [warning] = self.flushWarnings() self.assertEqual(warning["category"], DeprecationWarning) self.assertIn("twisted.web.pages.notFound", warning["message"]) def test_deprecatedForbiddenResource(self) -> None: """ The public C{twisted.web.resource.ForbiddenResource} alias for the corresponding C{_Unsafe} class produce a deprecation warning when imported. """ from twisted.web.resource import ForbiddenResource self.assertIs(ForbiddenResource, self.forbiddenResource) [warning] = self.flushWarnings() self.assertEqual(warning["category"], DeprecationWarning) self.assertIn("twisted.web.pages.forbidden", warning["message"]) def test_getChild(self) -> None: """ The C{getChild} method of L{ErrorPage} returns the L{ErrorPage} it is called on. """ page = self.errorPage(321, "foo", "bar") self.assertIdentical(page.getChild(b"name", object()), page) def _pageRenderingTest( self, page: Resource, code: int, brief: str, detail: str ) -> None: request = DummyRequest([b""]) template = ( "\n" "<html>\n" " <head><title>%s - %s</title></head>\n" " <body>\n" " <h1>%s</h1>\n" " <p>%s</p>\n" " </body>\n" "</html>\n" ) expected = template % (code, brief, brief, detail) self.assertEqual(page.render(request), expected.encode("utf-8")) self.assertEqual(request.responseCode, code) self.assertEqual( request.responseHeaders, Headers({b"content-type": [b"text/html; charset=utf-8"]}), ) def test_errorPageRendering(self) -> None: """ L{ErrorPage.render} returns a C{bytes} describing the error defined by the response code and message passed to L{ErrorPage.__init__}. It also uses that response code to set the response code on the L{Request} passed in. """ code = 321 brief = "brief description text" detail = "much longer text might go here" page = self.errorPage(code, brief, detail) self._pageRenderingTest(page, code, brief, detail) def test_noResourceRendering(self) -> None: """ L{NoResource} sets the HTTP I{NOT FOUND} code. """ detail = "long message" page = self.noResource(detail) self._pageRenderingTest(page, NOT_FOUND, "No Such Resource", detail) def test_forbiddenResourceRendering(self) -> None: """ L{ForbiddenResource} sets the HTTP I{FORBIDDEN} code. """ detail = "longer message" page = self.forbiddenResource(detail) self._pageRenderingTest(page, FORBIDDEN, "Forbidden Resource", detail) class DynamicChild(Resource): """ A L{Resource} to be created on the fly by L{DynamicChildren}. """ def __init__(self, path: bytes, request: IRequest) -> None: Resource.__init__(self) self.path = path self.request = request class DynamicChildren(Resource): """ A L{Resource} with dynamic children. """ def getChild(self, path: bytes, request: IRequest) -> DynamicChild: return DynamicChild(path, request) class BytesReturnedRenderable(Resource): """ A L{Resource} with minimal capabilities to render a response. """ def __init__(self, response: bytes) -> None: """ @param response: A C{bytes} object giving the value to return from C{render_GET}. """ Resource.__init__(self) self._response = response def render_GET(self, request: object) -> bytes: """ Render a response to a I{GET} request by returning a short byte string to be written by the server. """ return self._response class ImplicitAllowedMethods(Resource): """ A L{Resource} which implicitly defines its allowed methods by defining renderers to handle them. """ def render_GET(self, request: object) -> None: pass def render_PUT(self, request: object) -> None: pass class ResourceTests(TestCase): """ Tests for L{Resource}. """ def test_staticChildren(self) -> None: """ L{Resource.putChild} adds a I{static} child to the resource. That child is returned from any call to L{Resource.getChildWithDefault} for the child's path. """ resource = Resource() child = Resource() sibling = Resource() resource.putChild(b"foo", child) resource.putChild(b"bar", sibling) self.assertIdentical( child, resource.getChildWithDefault(b"foo", DummyRequest([])) ) def test_dynamicChildren(self) -> None: """ L{Resource.getChildWithDefault} delegates to L{Resource.getChild} when the requested path is not associated with any static child. """ path = b"foo" request = DummyRequest([]) resource = DynamicChildren() child = resource.getChildWithDefault(path, request) self.assertIsInstance(child, DynamicChild) self.assertEqual(child.path, path) self.assertIdentical(child.request, request) def test_staticChildPathType(self) -> None: """ Test that passing the wrong type to putChild results in a warning, and a failure in Python 3 """ resource = Resource() child = Resource() sibling = Resource() self.assertRaises(TypeError, resource.putChild, "foo", child) self.assertRaises(TypeError, resource.putChild, None, sibling) def test_defaultHEAD(self) -> None: """ When not otherwise overridden, L{Resource.render} treats a I{HEAD} request as if it were a I{GET} request. """ expected = b"insert response here" request = DummyRequest([]) request.method = b"HEAD" resource = BytesReturnedRenderable(expected) self.assertEqual(expected, resource.render(request)) def test_explicitAllowedMethods(self) -> None: """ The L{UnsupportedMethod} raised by L{Resource.render} for an unsupported request method has a C{allowedMethods} attribute set to the value of the C{allowedMethods} attribute of the L{Resource}, if it has one. """ expected = [b"GET", b"HEAD", b"PUT"] resource = Resource() resource.allowedMethods = expected request = DummyRequest([]) request.method = b"FICTIONAL" exc = self.assertRaises(UnsupportedMethod, resource.render, request) self.assertEqual(set(expected), set(exc.allowedMethods)) def test_implicitAllowedMethods(self) -> None: """ The L{UnsupportedMethod} raised by L{Resource.render} for an unsupported request method has a C{allowedMethods} attribute set to a list of the methods supported by the L{Resource}, as determined by the I{render_}-prefixed methods which it defines, if C{allowedMethods} is not explicitly defined by the L{Resource}. """ expected = {b"GET", b"HEAD", b"PUT"} resource = ImplicitAllowedMethods() request = DummyRequest([]) request.method = b"FICTIONAL" exc = self.assertRaises(UnsupportedMethod, resource.render, request) self.assertEqual(expected, set(exc.allowedMethods)) class GetChildForRequestTests(TestCase): """ Tests for L{getChildForRequest}. """ def test_exhaustedPostPath(self) -> None: """ L{getChildForRequest} returns whatever resource has been reached by the time the request's C{postpath} is empty. """ request = DummyRequest([]) resource = Resource() result = getChildForRequest(resource, request) self.assertIdentical(resource, result) def test_leafResource(self) -> None: """ L{getChildForRequest} returns the first resource it encounters with a C{isLeaf} attribute set to C{True}. """ request = DummyRequest([b"foo", b"bar"]) resource = Resource() resource.isLeaf = True result = getChildForRequest(resource, request) self.assertIdentical(resource, result) def test_postPathToPrePath(self) -> None: """ As path segments from the request are traversed, they are taken from C{postpath} and put into C{prepath}. """ request = DummyRequest([b"foo", b"bar"]) root = Resource() child = Resource() child.isLeaf = True root.putChild(b"foo", child) self.assertIdentical(child, getChildForRequest(root, request)) self.assertEqual(request.prepath, [b"foo"]) self.assertEqual(request.postpath, [b"bar"])