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

Extra type annotations in test_server #13124

Merged
merged 3 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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