events: Add heartbeat events to tests and documentation.

Heartbeat events are an important part of the API, even though they
are noops, so it's important to document them.
This commit is contained in:
Tim Abbott
2021-07-01 17:13:55 -07:00
parent 3da6f3c0af
commit 64aa8f80a0
5 changed files with 59 additions and 1 deletions

View File

@@ -288,6 +288,23 @@ def check_has_zoom_token(
assert event["value"] == value
heartbeat_event = event_dict_type(
required_keys=[
# force vertical
("type", Equals("heartbeat")),
]
)
_check_hearbeat = make_checker(heartbeat_event)
def check_heartbeat(
# force vertical
var_name: str,
event: Dict[str, object],
) -> None:
_check_hearbeat(var_name, event)
_hotspot = DictType(
required_keys=[
# force vertical

View File

@@ -613,6 +613,10 @@ def apply_event(
if stream_dict["first_message_id"] is None:
stream_dict["first_message_id"] = event["message"]["id"]
elif event["type"] == "heartbeat":
# It may be impossible for a heartbeat event to actually reach
# this code path. But in any case, they're noops.
pass
elif event["type"] == "hotspots":
state["hotspots"] = event["hotspots"]
elif event["type"] == "custom_profile_fields":

View File

@@ -1803,6 +1803,24 @@ paths:
],
"id": 0,
}
- type: object
additionalProperties: false
description: |
Heartbeat events are sent by the server to avoid
longpolling connections being affected by networks that
kill idle HTTP connections.
Clients do not need to do anything to process these
events, beyond the common `last_event_id` accounting.
properties:
id:
$ref: "#/components/schemas/EventIdSchema"
type:
allOf:
- $ref: "#/components/schemas/EventTypeSchema"
- enum:
- heartbeat
example: {"type": "heartbeat", "id": 0}
- type: object
additionalProperties: false
description: |

View File

@@ -111,6 +111,7 @@ from zerver.lib.event_schema import (
check_default_streams,
check_delete_message,
check_has_zoom_token,
check_heartbeat,
check_hotspots,
check_invites_changed,
check_message,
@@ -200,9 +201,11 @@ from zerver.models import (
get_user_by_delivery_email,
)
from zerver.openapi.openapi import validate_against_openapi_schema
from zerver.tornado.django_api import send_event
from zerver.tornado.event_queue import (
allocate_client_descriptor,
clear_client_event_queues_for_testing,
create_heartbeat_event,
send_restart_events,
)
from zerver.views.realm_playgrounds import access_playground_by_id
@@ -593,6 +596,17 @@ class NormalActionsTest(BaseAction):
)
check_reaction_add("events[0]", events[0])
def test_heartbeat_event(self) -> None:
events = self.verify_action(
lambda: send_event(
self.user_profile.realm,
create_heartbeat_event(),
[self.user_profile.id],
),
state_change_expected=False,
)
check_heartbeat("events[0]", events[0])
def test_add_submessage(self) -> None:
cordelia = self.example_user("cordelia")
stream_name = "Verona"

View File

@@ -75,6 +75,10 @@ MAX_QUEUE_TIMEOUT_SECS = 7 * 24 * 60 * 60
HEARTBEAT_MIN_FREQ_SECS = 45
def create_heartbeat_event() -> Dict[str, str]:
return dict(type="heartbeat")
class ClientDescriptor:
def __init__(
self,
@@ -234,7 +238,8 @@ class ClientDescriptor:
def timeout_callback() -> None:
self._timeout_handle = None
# All clients get heartbeat events
self.add_event(dict(type="heartbeat"))
heartbeat_event = create_heartbeat_event()
self.add_event(heartbeat_event)
ioloop = tornado.ioloop.IOLoop.instance()
interval = HEARTBEAT_MIN_FREQ_SECS + random.randint(0, 10)