Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Extra type annotations in test_server (#13124)
Browse files Browse the repository at this point in the history
  • Loading branch information
David Robertson authored Jun 28, 2022
1 parent 6b99a66 commit f114556
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 37 deletions.
1 change: 1 addition & 0 deletions changelog.d/13124.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add type annotations to `tests.test_server`.
3 changes: 3 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ disallow_untyped_defs = False
[mypy-tests.handlers.test_user_directory]
disallow_untyped_defs = True

[mypy-tests.test_server]
disallow_untyped_defs = True

[mypy-tests.state.test_profile]
disallow_untyped_defs = True

Expand Down
81 changes: 44 additions & 37 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import re
from http import HTTPStatus
from typing import Tuple
from typing import Awaitable, Callable, Dict, NoReturn, Optional, Tuple

from twisted.internet.defer import Deferred
from twisted.web.resource import Resource
Expand All @@ -36,6 +36,7 @@
from tests import unittest
from tests.http.server._base import test_disconnect
from tests.server import (
FakeChannel,
FakeSite,
ThreadedMemoryReactorClock,
make_request,
Expand All @@ -44,7 +45,7 @@


class JsonResourceTests(unittest.TestCase):
def setUp(self):
def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock()
self.hs_clock = Clock(self.reactor)
self.homeserver = setup_test_homeserver(
Expand All @@ -54,15 +55,17 @@ def setUp(self):
reactor=self.reactor,
)

def test_handler_for_request(self):
def test_handler_for_request(self) -> None:
"""
JsonResource.handler_for_request gives correctly decoded URL args to
the callback, while Twisted will give the raw bytes of URL query
arguments.
"""
got_kwargs = {}

def _callback(request, **kwargs):
def _callback(
request: SynapseRequest, **kwargs: object
) -> Tuple[int, Dict[str, object]]:
got_kwargs.update(kwargs)
return 200, kwargs

Expand All @@ -83,13 +86,13 @@ def _callback(request, **kwargs):

self.assertEqual(got_kwargs, {"room_id": "\N{SNOWMAN}"})

def test_callback_direct_exception(self):
def test_callback_direct_exception(self) -> None:
"""
If the web callback raises an uncaught exception, it will be translated
into a 500.
"""

def _callback(request, **kwargs):
def _callback(request: SynapseRequest, **kwargs: object) -> NoReturn:
raise Exception("boo")

res = JsonResource(self.homeserver)
Expand All @@ -103,17 +106,17 @@ def _callback(request, **kwargs):

self.assertEqual(channel.result["code"], b"500")

def test_callback_indirect_exception(self):
def test_callback_indirect_exception(self) -> None:
"""
If the web callback raises an uncaught exception in a Deferred, it will
be translated into a 500.
"""

def _throw(*args):
def _throw(*args: object) -> NoReturn:
raise Exception("boo")

def _callback(request, **kwargs):
d = Deferred()
def _callback(request: SynapseRequest, **kwargs: object) -> "Deferred[None]":
d: "Deferred[None]" = Deferred()
d.addCallback(_throw)
self.reactor.callLater(0.5, d.callback, True)
return make_deferred_yieldable(d)
Expand All @@ -129,13 +132,13 @@ def _callback(request, **kwargs):

self.assertEqual(channel.result["code"], b"500")

def test_callback_synapseerror(self):
def test_callback_synapseerror(self) -> None:
"""
If the web callback raises a SynapseError, it returns the appropriate
status code and message set in it.
"""

def _callback(request, **kwargs):
def _callback(request: SynapseRequest, **kwargs: object) -> NoReturn:
raise SynapseError(403, "Forbidden!!one!", Codes.FORBIDDEN)

res = JsonResource(self.homeserver)
Expand All @@ -151,12 +154,12 @@ def _callback(request, **kwargs):
self.assertEqual(channel.json_body["error"], "Forbidden!!one!")
self.assertEqual(channel.json_body["errcode"], "M_FORBIDDEN")

def test_no_handler(self):
def test_no_handler(self) -> None:
"""
If there is no handler to process the request, Synapse will return 400.
"""

def _callback(request, **kwargs):
def _callback(request: SynapseRequest, **kwargs: object) -> None:
"""
Not ever actually called!
"""
Expand All @@ -175,14 +178,16 @@ def _callback(request, **kwargs):
self.assertEqual(channel.json_body["error"], "Unrecognized request")
self.assertEqual(channel.json_body["errcode"], "M_UNRECOGNIZED")

def test_head_request(self):
def test_head_request(self) -> None:
"""
JsonResource.handler_for_request gives correctly decoded URL args to
the callback, while Twisted will give the raw bytes of URL query
arguments.
"""

def _callback(request, **kwargs):
def _callback(
request: SynapseRequest, **kwargs: object
) -> Tuple[int, Dict[str, object]]:
return 200, {"result": True}

res = JsonResource(self.homeserver)
Expand All @@ -203,20 +208,21 @@ def _callback(request, **kwargs):


class OptionsResourceTests(unittest.TestCase):
def setUp(self):
def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock()

class DummyResource(Resource):
isLeaf = True

def render(self, request):
return request.path
def render(self, request: SynapseRequest) -> bytes:
# Type-ignore: mypy thinks request.path is Optional[Any], not bytes.
return request.path # type: ignore[return-value]

# Setup a resource with some children.
self.resource = OptionsResource()
self.resource.putChild(b"res", DummyResource())

def _make_request(self, method, path):
def _make_request(self, method: bytes, path: bytes) -> FakeChannel:
"""Create a request from the method/path and return a channel with the response."""
# Create a site and query for the resource.
site = SynapseSite(
Expand All @@ -233,7 +239,7 @@ def _make_request(self, method, path):
channel = make_request(self.reactor, site, method, path, shorthand=False)
return channel

def test_unknown_options_request(self):
def test_unknown_options_request(self) -> None:
"""An OPTIONS requests to an unknown URL still returns 204 No Content."""
channel = self._make_request(b"OPTIONS", b"/foo/")
self.assertEqual(channel.result["code"], b"204")
Expand All @@ -253,7 +259,7 @@ def test_unknown_options_request(self):
"has CORS Headers header",
)

def test_known_options_request(self):
def test_known_options_request(self) -> None:
"""An OPTIONS requests to an known URL still returns 204 No Content."""
channel = self._make_request(b"OPTIONS", b"/res/")
self.assertEqual(channel.result["code"], b"204")
Expand All @@ -273,12 +279,12 @@ def test_known_options_request(self):
"has CORS Headers header",
)

def test_unknown_request(self):
def test_unknown_request(self) -> None:
"""A non-OPTIONS request to an unknown URL should 404."""
channel = self._make_request(b"GET", b"/foo/")
self.assertEqual(channel.result["code"], b"404")

def test_known_request(self):
def test_known_request(self) -> None:
"""A non-OPTIONS request to an known URL should query the proper resource."""
channel = self._make_request(b"GET", b"/res/")
self.assertEqual(channel.result["code"], b"200")
Expand All @@ -287,16 +293,17 @@ def test_known_request(self):

class WrapHtmlRequestHandlerTests(unittest.TestCase):
class TestResource(DirectServeHtmlResource):
callback = None
callback: Optional[Callable[..., Awaitable[None]]]

async def _async_render_GET(self, request):
async def _async_render_GET(self, request: SynapseRequest) -> None:
assert self.callback is not None
await self.callback(request)

def setUp(self):
def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock()

def test_good_response(self):
async def callback(request):
def test_good_response(self) -> None:
async def callback(request: SynapseRequest) -> None:
request.write(b"response")
request.finish()

Expand All @@ -311,13 +318,13 @@ async def callback(request):
body = channel.result["body"]
self.assertEqual(body, b"response")

def test_redirect_exception(self):
def test_redirect_exception(self) -> None:
"""
If the callback raises a RedirectException, it is turned into a 30x
with the right location.
"""

async def callback(request, **kwargs):
async def callback(request: SynapseRequest, **kwargs: object) -> None:
raise RedirectException(b"/look/an/eagle", 301)

res = WrapHtmlRequestHandlerTests.TestResource()
Expand All @@ -332,13 +339,13 @@ async def callback(request, **kwargs):
location_headers = [v for k, v in headers if k == b"Location"]
self.assertEqual(location_headers, [b"/look/an/eagle"])

def test_redirect_exception_with_cookie(self):
def test_redirect_exception_with_cookie(self) -> None:
"""
If the callback raises a RedirectException which sets a cookie, that is
returned too
"""

async def callback(request, **kwargs):
async def callback(request: SynapseRequest, **kwargs: object) -> NoReturn:
e = RedirectException(b"/no/over/there", 304)
e.cookies.append(b"session=yespls")
raise e
Expand All @@ -357,10 +364,10 @@ async def callback(request, **kwargs):
cookies_headers = [v for k, v in headers if k == b"Set-Cookie"]
self.assertEqual(cookies_headers, [b"session=yespls"])

def test_head_request(self):
def test_head_request(self) -> None:
"""A head request should work by being turned into a GET request."""

async def callback(request):
async def callback(request: SynapseRequest) -> None:
request.write(b"response")
request.finish()

Expand Down Expand Up @@ -410,7 +417,7 @@ async def _async_render_POST(self, request: SynapseRequest) -> Tuple[int, bytes]
class DirectServeJsonResourceCancellationTests(unittest.TestCase):
"""Tests for `DirectServeJsonResource` cancellation."""

def setUp(self):
def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock()
self.clock = Clock(self.reactor)
self.resource = CancellableDirectServeJsonResource(self.clock)
Expand Down Expand Up @@ -444,7 +451,7 @@ def test_uncancellable_disconnect(self) -> None:
class DirectServeHtmlResourceCancellationTests(unittest.TestCase):
"""Tests for `DirectServeHtmlResource` cancellation."""

def setUp(self):
def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock()
self.clock = Clock(self.reactor)
self.resource = CancellableDirectServeHtmlResource(self.clock)
Expand Down

0 comments on commit f114556

Please sign in to comment.