Extra type annotations in test_server (#13124)

This commit is contained in:
David Robertson 2022-06-28 14:12:17 +02:00 committed by GitHub
parent 6b99a66fe0
commit f1145563f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 37 deletions

1
changelog.d/13124.misc Normal file
View file

@ -0,0 +1 @@
Add type annotations to `tests.test_server`.

View file

@ -113,6 +113,9 @@ disallow_untyped_defs = False
[mypy-tests.handlers.test_user_directory] [mypy-tests.handlers.test_user_directory]
disallow_untyped_defs = True disallow_untyped_defs = True
[mypy-tests.test_server]
disallow_untyped_defs = True
[mypy-tests.state.test_profile] [mypy-tests.state.test_profile]
disallow_untyped_defs = True disallow_untyped_defs = True

View file

@ -14,7 +14,7 @@
import re import re
from http import HTTPStatus 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.internet.defer import Deferred
from twisted.web.resource import Resource from twisted.web.resource import Resource
@ -36,6 +36,7 @@ from synapse.util import Clock
from tests import unittest from tests import unittest
from tests.http.server._base import test_disconnect from tests.http.server._base import test_disconnect
from tests.server import ( from tests.server import (
FakeChannel,
FakeSite, FakeSite,
ThreadedMemoryReactorClock, ThreadedMemoryReactorClock,
make_request, make_request,
@ -44,7 +45,7 @@ from tests.server import (
class JsonResourceTests(unittest.TestCase): class JsonResourceTests(unittest.TestCase):
def setUp(self): def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock() self.reactor = ThreadedMemoryReactorClock()
self.hs_clock = Clock(self.reactor) self.hs_clock = Clock(self.reactor)
self.homeserver = setup_test_homeserver( self.homeserver = setup_test_homeserver(
@ -54,7 +55,7 @@ class JsonResourceTests(unittest.TestCase):
reactor=self.reactor, 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 JsonResource.handler_for_request gives correctly decoded URL args to
the callback, while Twisted will give the raw bytes of URL query the callback, while Twisted will give the raw bytes of URL query
@ -62,7 +63,9 @@ class JsonResourceTests(unittest.TestCase):
""" """
got_kwargs = {} got_kwargs = {}
def _callback(request, **kwargs): def _callback(
request: SynapseRequest, **kwargs: object
) -> Tuple[int, Dict[str, object]]:
got_kwargs.update(kwargs) got_kwargs.update(kwargs)
return 200, kwargs return 200, kwargs
@ -83,13 +86,13 @@ class JsonResourceTests(unittest.TestCase):
self.assertEqual(got_kwargs, {"room_id": "\N{SNOWMAN}"}) 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 If the web callback raises an uncaught exception, it will be translated
into a 500. into a 500.
""" """
def _callback(request, **kwargs): def _callback(request: SynapseRequest, **kwargs: object) -> NoReturn:
raise Exception("boo") raise Exception("boo")
res = JsonResource(self.homeserver) res = JsonResource(self.homeserver)
@ -103,17 +106,17 @@ class JsonResourceTests(unittest.TestCase):
self.assertEqual(channel.result["code"], b"500") 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 If the web callback raises an uncaught exception in a Deferred, it will
be translated into a 500. be translated into a 500.
""" """
def _throw(*args): def _throw(*args: object) -> NoReturn:
raise Exception("boo") raise Exception("boo")
def _callback(request, **kwargs): def _callback(request: SynapseRequest, **kwargs: object) -> "Deferred[None]":
d = Deferred() d: "Deferred[None]" = Deferred()
d.addCallback(_throw) d.addCallback(_throw)
self.reactor.callLater(0.5, d.callback, True) self.reactor.callLater(0.5, d.callback, True)
return make_deferred_yieldable(d) return make_deferred_yieldable(d)
@ -129,13 +132,13 @@ class JsonResourceTests(unittest.TestCase):
self.assertEqual(channel.result["code"], b"500") 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 If the web callback raises a SynapseError, it returns the appropriate
status code and message set in it. 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) raise SynapseError(403, "Forbidden!!one!", Codes.FORBIDDEN)
res = JsonResource(self.homeserver) res = JsonResource(self.homeserver)
@ -151,12 +154,12 @@ class JsonResourceTests(unittest.TestCase):
self.assertEqual(channel.json_body["error"], "Forbidden!!one!") self.assertEqual(channel.json_body["error"], "Forbidden!!one!")
self.assertEqual(channel.json_body["errcode"], "M_FORBIDDEN") 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. 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! Not ever actually called!
""" """
@ -175,14 +178,16 @@ class JsonResourceTests(unittest.TestCase):
self.assertEqual(channel.json_body["error"], "Unrecognized request") self.assertEqual(channel.json_body["error"], "Unrecognized request")
self.assertEqual(channel.json_body["errcode"], "M_UNRECOGNIZED") 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 JsonResource.handler_for_request gives correctly decoded URL args to
the callback, while Twisted will give the raw bytes of URL query the callback, while Twisted will give the raw bytes of URL query
arguments. arguments.
""" """
def _callback(request, **kwargs): def _callback(
request: SynapseRequest, **kwargs: object
) -> Tuple[int, Dict[str, object]]:
return 200, {"result": True} return 200, {"result": True}
res = JsonResource(self.homeserver) res = JsonResource(self.homeserver)
@ -203,20 +208,21 @@ class JsonResourceTests(unittest.TestCase):
class OptionsResourceTests(unittest.TestCase): class OptionsResourceTests(unittest.TestCase):
def setUp(self): def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock() self.reactor = ThreadedMemoryReactorClock()
class DummyResource(Resource): class DummyResource(Resource):
isLeaf = True isLeaf = True
def render(self, request): def render(self, request: SynapseRequest) -> bytes:
return request.path # Type-ignore: mypy thinks request.path is Optional[Any], not bytes.
return request.path # type: ignore[return-value]
# Setup a resource with some children. # Setup a resource with some children.
self.resource = OptionsResource() self.resource = OptionsResource()
self.resource.putChild(b"res", DummyResource()) 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 request from the method/path and return a channel with the response."""
# Create a site and query for the resource. # Create a site and query for the resource.
site = SynapseSite( site = SynapseSite(
@ -233,7 +239,7 @@ class OptionsResourceTests(unittest.TestCase):
channel = make_request(self.reactor, site, method, path, shorthand=False) channel = make_request(self.reactor, site, method, path, shorthand=False)
return channel 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.""" """An OPTIONS requests to an unknown URL still returns 204 No Content."""
channel = self._make_request(b"OPTIONS", b"/foo/") channel = self._make_request(b"OPTIONS", b"/foo/")
self.assertEqual(channel.result["code"], b"204") self.assertEqual(channel.result["code"], b"204")
@ -253,7 +259,7 @@ class OptionsResourceTests(unittest.TestCase):
"has CORS Headers header", "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.""" """An OPTIONS requests to an known URL still returns 204 No Content."""
channel = self._make_request(b"OPTIONS", b"/res/") channel = self._make_request(b"OPTIONS", b"/res/")
self.assertEqual(channel.result["code"], b"204") self.assertEqual(channel.result["code"], b"204")
@ -273,12 +279,12 @@ class OptionsResourceTests(unittest.TestCase):
"has CORS Headers header", "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.""" """A non-OPTIONS request to an unknown URL should 404."""
channel = self._make_request(b"GET", b"/foo/") channel = self._make_request(b"GET", b"/foo/")
self.assertEqual(channel.result["code"], b"404") 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.""" """A non-OPTIONS request to an known URL should query the proper resource."""
channel = self._make_request(b"GET", b"/res/") channel = self._make_request(b"GET", b"/res/")
self.assertEqual(channel.result["code"], b"200") self.assertEqual(channel.result["code"], b"200")
@ -287,16 +293,17 @@ class OptionsResourceTests(unittest.TestCase):
class WrapHtmlRequestHandlerTests(unittest.TestCase): class WrapHtmlRequestHandlerTests(unittest.TestCase):
class TestResource(DirectServeHtmlResource): 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) await self.callback(request)
def setUp(self): def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock() self.reactor = ThreadedMemoryReactorClock()
def test_good_response(self): def test_good_response(self) -> None:
async def callback(request): async def callback(request: SynapseRequest) -> None:
request.write(b"response") request.write(b"response")
request.finish() request.finish()
@ -311,13 +318,13 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
body = channel.result["body"] body = channel.result["body"]
self.assertEqual(body, b"response") 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 If the callback raises a RedirectException, it is turned into a 30x
with the right location. with the right location.
""" """
async def callback(request, **kwargs): async def callback(request: SynapseRequest, **kwargs: object) -> None:
raise RedirectException(b"/look/an/eagle", 301) raise RedirectException(b"/look/an/eagle", 301)
res = WrapHtmlRequestHandlerTests.TestResource() res = WrapHtmlRequestHandlerTests.TestResource()
@ -332,13 +339,13 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
location_headers = [v for k, v in headers if k == b"Location"] location_headers = [v for k, v in headers if k == b"Location"]
self.assertEqual(location_headers, [b"/look/an/eagle"]) 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 If the callback raises a RedirectException which sets a cookie, that is
returned too returned too
""" """
async def callback(request, **kwargs): async def callback(request: SynapseRequest, **kwargs: object) -> NoReturn:
e = RedirectException(b"/no/over/there", 304) e = RedirectException(b"/no/over/there", 304)
e.cookies.append(b"session=yespls") e.cookies.append(b"session=yespls")
raise e raise e
@ -357,10 +364,10 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
cookies_headers = [v for k, v in headers if k == b"Set-Cookie"] cookies_headers = [v for k, v in headers if k == b"Set-Cookie"]
self.assertEqual(cookies_headers, [b"session=yespls"]) 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.""" """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.write(b"response")
request.finish() request.finish()
@ -410,7 +417,7 @@ class CancellableDirectServeHtmlResource(DirectServeHtmlResource):
class DirectServeJsonResourceCancellationTests(unittest.TestCase): class DirectServeJsonResourceCancellationTests(unittest.TestCase):
"""Tests for `DirectServeJsonResource` cancellation.""" """Tests for `DirectServeJsonResource` cancellation."""
def setUp(self): def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock() self.reactor = ThreadedMemoryReactorClock()
self.clock = Clock(self.reactor) self.clock = Clock(self.reactor)
self.resource = CancellableDirectServeJsonResource(self.clock) self.resource = CancellableDirectServeJsonResource(self.clock)
@ -444,7 +451,7 @@ class DirectServeJsonResourceCancellationTests(unittest.TestCase):
class DirectServeHtmlResourceCancellationTests(unittest.TestCase): class DirectServeHtmlResourceCancellationTests(unittest.TestCase):
"""Tests for `DirectServeHtmlResource` cancellation.""" """Tests for `DirectServeHtmlResource` cancellation."""
def setUp(self): def setUp(self) -> None:
self.reactor = ThreadedMemoryReactorClock() self.reactor = ThreadedMemoryReactorClock()
self.clock = Clock(self.reactor) self.clock = Clock(self.reactor)
self.resource = CancellableDirectServeHtmlResource(self.clock) self.resource = CancellableDirectServeHtmlResource(self.clock)