Skip to content

Commit 6dc7600

Browse files
authored
fix(crons): Serialize the config type correctly (#85211)
Applies the serialization to the config that the frontend has been typed to expect. Specifically the schedule type being served as an integer, but expected as a string.
1 parent 592ce76 commit 6dc7600

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

src/sentry/monitors/serializers.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from collections import defaultdict
22
from collections.abc import MutableMapping, Sequence
33
from datetime import datetime
4-
from typing import Any, Literal, TypedDict
4+
from typing import Any, Literal, TypedDict, cast
55

66
from django.db.models import prefetch_related_objects
77

@@ -17,6 +17,7 @@
1717
MonitorEnvironment,
1818
MonitorIncident,
1919
MonitorStatus,
20+
ScheduleType,
2021
)
2122
from sentry.monitors.processing_errors.errors import (
2223
CheckinProcessingError,
@@ -276,7 +277,7 @@ class MonitorCheckInSerializerResponse(MonitorCheckInSerializerResponseOptional)
276277
duration: int
277278
dateCreated: datetime
278279
expectedTime: datetime
279-
monitorConfig: Any
280+
monitorConfig: MonitorConfigSerializerResponse
280281

281282

282283
@register(MonitorCheckIn)
@@ -330,14 +331,19 @@ def get_attrs(self, item_list, user, **kwargs):
330331
return attrs
331332

332333
def serialize(self, obj, attrs, user, **kwargs) -> MonitorCheckInSerializerResponse:
334+
config = obj.monitor_config.copy() if obj.monitor_config else {}
335+
if "schedule_type" in config:
336+
# XXX: We don't use monitor.get_schedule_type_display() in case it differs from the
337+
# config saved on the check-in
338+
config["schedule_type"] = ScheduleType.get_name(config["schedule_type"])
333339
result: MonitorCheckInSerializerResponse = {
334340
"id": str(obj.guid),
335341
"environment": attrs["environment_name"],
336342
"status": obj.get_status_display(),
337343
"duration": obj.duration,
338344
"dateCreated": obj.date_added,
339345
"expectedTime": obj.expected_time,
340-
"monitorConfig": obj.monitor_config or {},
346+
"monitorConfig": cast(MonitorConfigSerializerResponse, config),
341347
}
342348

343349
if self._expand("groups"):

src/sentry/testutils/fixtures.py

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from sentry.models.team import Team
2727
from sentry.monitors.models import (
2828
Monitor,
29+
MonitorCheckIn,
2930
MonitorEnvironment,
3031
MonitorIncident,
3132
MonitorType,
@@ -465,6 +466,9 @@ def create_monitor_environment(self, **kwargs):
465466
def create_monitor_incident(self, **kwargs):
466467
return MonitorIncident.objects.create(**kwargs)
467468

469+
def create_monitor_checkin(self, **kwargs):
470+
return MonitorCheckIn.objects.create(**kwargs)
471+
468472
def create_external_user(self, user=None, organization=None, integration=None, **kwargs):
469473
if not user:
470474
user = self.user

tests/sentry/monitors/endpoints/test_base_monitor_checkin_index.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from sentry.models.environment import Environment
77
from sentry.models.group import Group
8-
from sentry.monitors.models import CheckInStatus, MonitorCheckIn, MonitorStatus
8+
from sentry.monitors.models import CheckInStatus, MonitorCheckIn, MonitorStatus, ScheduleType
99
from sentry.testutils.cases import MonitorTestCase
1010
from sentry.testutils.helpers.datetime import freeze_time
1111
from sentry.testutils.skips import requires_snuba
@@ -225,3 +225,42 @@ def test_trace_ids(self):
225225
assert resp.data[0]["groups"] == []
226226
assert resp.data[1]["id"] == str(checkin1.guid)
227227
assert resp.data[1]["groups"] == [{"id": group.id, "shortId": group.qualified_short_id}]
228+
229+
def test_serializes_monitor_config_correctly(self):
230+
monitor = self.create_monitor(project=self.project)
231+
config = {
232+
"schedule": "0 0 * * *",
233+
"schedule_type": ScheduleType.CRONTAB,
234+
"timezone": "US/Arizona",
235+
"max_runtime": None,
236+
"checkin_margin": None,
237+
}
238+
monitor_environment = self._create_monitor_environment(monitor)
239+
self.create_monitor_checkin(
240+
monitor=monitor,
241+
monitor_environment=monitor_environment,
242+
project_id=self.project.id,
243+
date_added=monitor.date_added - timedelta(minutes=2),
244+
status=CheckInStatus.OK,
245+
monitor_config=config,
246+
)
247+
# Mutating the monitor config to test that the check-in config is used
248+
monitor.config = {
249+
"schedule": "0 * * * *",
250+
"schedule_type": ScheduleType.INTERVAL,
251+
"timezone": "CA/Toronto",
252+
"max_runtime": 1000,
253+
"checkin_margin": 100,
254+
}
255+
monitor.save()
256+
response = self.get_success_response(
257+
self.project.organization.slug,
258+
monitor.slug,
259+
)
260+
assert response.data[0]["monitorConfig"]["schedule_type"] == ScheduleType.get_name(
261+
config["schedule_type"]
262+
)
263+
assert response.data[0]["monitorConfig"]["schedule"] == config["schedule"]
264+
assert response.data[0]["monitorConfig"]["timezone"] == config["timezone"]
265+
assert response.data[0]["monitorConfig"]["max_runtime"] == config["max_runtime"]
266+
assert response.data[0]["monitorConfig"]["checkin_margin"] == config["checkin_margin"]

0 commit comments

Comments
 (0)