tornado: Move the /notify-tornado endpoint, and document it better.

This commit is contained in:
Alex Vandiver
2024-02-08 19:10:25 +00:00
committed by Tim Abbott
parent 3f8a0c968a
commit 84fa9be73a
5 changed files with 16 additions and 10 deletions

View File

@@ -227,9 +227,10 @@ class EventsEndpointTest(ZulipTestCase):
self.assert_json_error(result, "User not authorized for this query") self.assert_json_error(result, "User not authorized for this query")
def test_tornado_endpoint(self) -> None: def test_tornado_endpoint(self) -> None:
# This test is mostly intended to get minimal coverage on # This test is mostly intended to get minimal coverage on the
# the /notify_tornado endpoint, so we can have 100% URL coverage, # /api/internal/notify_tornado endpoint (only used in
# but it does exercise a little bit of the codepath. # puppeteer tests), so we can have 100% URL coverage, but it
# does exercise a little bit of the codepath.
post_data = dict( post_data = dict(
data=orjson.dumps( data=orjson.dumps(
dict( dict(
@@ -243,7 +244,7 @@ class EventsEndpointTest(ZulipTestCase):
req = HostRequestMock(post_data) req = HostRequestMock(post_data)
req.META["REMOTE_ADDR"] = "127.0.0.1" req.META["REMOTE_ADDR"] = "127.0.0.1"
with self.assertRaises(RequestVariableMissingError) as context: with self.assertRaises(RequestVariableMissingError) as context:
result = self.client_post_request("/notify_tornado", req) result = self.client_post_request("/api/internal/notify_tornado", req)
self.assertEqual(str(context.exception), "Missing 'secret' argument") self.assertEqual(str(context.exception), "Missing 'secret' argument")
self.assertEqual(context.exception.http_status_code, 400) self.assertEqual(context.exception.http_status_code, 400)
@@ -251,21 +252,21 @@ class EventsEndpointTest(ZulipTestCase):
req = HostRequestMock(post_data, user_profile=None) req = HostRequestMock(post_data, user_profile=None)
req.META["REMOTE_ADDR"] = "127.0.0.1" req.META["REMOTE_ADDR"] = "127.0.0.1"
with self.assertRaises(AccessDeniedError) as access_denied_error: with self.assertRaises(AccessDeniedError) as access_denied_error:
result = self.client_post_request("/notify_tornado", req) result = self.client_post_request("/api/internal/notify_tornado", req)
self.assertEqual(str(access_denied_error.exception), "Access denied") self.assertEqual(str(access_denied_error.exception), "Access denied")
self.assertEqual(access_denied_error.exception.http_status_code, 403) self.assertEqual(access_denied_error.exception.http_status_code, 403)
post_data["secret"] = settings.SHARED_SECRET post_data["secret"] = settings.SHARED_SECRET
req = HostRequestMock(post_data, tornado_handler=dummy_handler) req = HostRequestMock(post_data, tornado_handler=dummy_handler)
req.META["REMOTE_ADDR"] = "127.0.0.1" req.META["REMOTE_ADDR"] = "127.0.0.1"
result = self.client_post_request("/notify_tornado", req) result = self.client_post_request("/api/internal/notify_tornado", req)
self.assert_json_success(result) self.assert_json_success(result)
post_data = dict(secret=settings.SHARED_SECRET) post_data = dict(secret=settings.SHARED_SECRET)
req = HostRequestMock(post_data, tornado_handler=dummy_handler) req = HostRequestMock(post_data, tornado_handler=dummy_handler)
req.META["REMOTE_ADDR"] = "127.0.0.1" req.META["REMOTE_ADDR"] = "127.0.0.1"
with self.assertRaises(RequestVariableMissingError) as context: with self.assertRaises(RequestVariableMissingError) as context:
result = self.client_post_request("/notify_tornado", req) result = self.client_post_request("/api/internal/notify_tornado", req)
self.assertEqual(str(context.exception), "Missing 'data' argument") self.assertEqual(str(context.exception), "Missing 'data' argument")
self.assertEqual(context.exception.http_status_code, 400) self.assertEqual(context.exception.http_status_code, 400)

View File

@@ -17,10 +17,10 @@ def create_tornado_application(*, autoreload: bool = False) -> tornado.web.Appli
django_handler.load_middleware() django_handler.load_middleware()
urls = ( urls = (
r"/notify_tornado",
r"/json/events", r"/json/events",
r"/api/v1/events", r"/api/v1/events",
r"/api/v1/events/internal", r"/api/v1/events/internal",
r"/api/internal/notify_tornado",
) )
return tornado.web.Application( return tornado.web.Application(

View File

@@ -155,9 +155,12 @@ def send_notification_http(port: int, data: Mapping[str, Any]) -> None:
process_notification(data) process_notification(data)
else: else:
# This codepath is only used when running full-stack puppeteer
# tests, which don't have RabbitMQ but do have a separate
# Tornado process.
tornado_url = get_tornado_url(port) tornado_url = get_tornado_url(port)
requests_client().post( requests_client().post(
tornado_url + "/notify_tornado", tornado_url + "/api/internal/notify_tornado",
data=dict(data=orjson.dumps(data), secret=settings.SHARED_SECRET), data=dict(data=orjson.dumps(data), secret=settings.SHARED_SECRET),
) )

View File

@@ -43,6 +43,8 @@ def in_tornado_thread(f: Callable[P, T]) -> Callable[P, T]:
def notify( def notify(
request: HttpRequest, data: Mapping[str, Any] = REQ(json_validator=check_dict([])) request: HttpRequest, data: Mapping[str, Any] = REQ(json_validator=check_dict([]))
) -> HttpResponse: ) -> HttpResponse:
# Only the puppeteer full-stack tests use this endpoint; it
# injects an event, as if read from RabbitMQ.
in_tornado_thread(process_notification)(data) in_tornado_thread(process_notification)(data)
return json_success(request) return json_success(request)

View File

@@ -745,7 +745,7 @@ urls += [
# #
# Since these views don't use rest_dispatch, they cannot have # Since these views don't use rest_dispatch, they cannot have
# asynchronous Tornado behavior. # asynchronous Tornado behavior.
path("notify_tornado", notify), path("api/internal/notify_tornado", notify),
path("api/v1/events/internal", get_events_internal), path("api/v1/events/internal", get_events_internal),
] ]