diff --git a/sentry_sdk/crons/decorator.py b/sentry_sdk/crons/decorator.py index 38653ca161..5bedcb48b0 100644 --- a/sentry_sdk/crons/decorator.py +++ b/sentry_sdk/crons/decorator.py @@ -5,7 +5,7 @@ from sentry_sdk.utils import now if TYPE_CHECKING: - from typing import Optional, Type + from typing import Any, Optional, Type from types import TracebackType if PY2: @@ -47,15 +47,18 @@ def test(arg): ``` """ - def __init__(self, monitor_slug=None): - # type: (Optional[str]) -> None + def __init__(self, monitor_slug=None, monitor_config=None): + # type: (Optional[str], Optional[dict[str, Any]]) -> None self.monitor_slug = monitor_slug + self.monitor_config = monitor_config def __enter__(self): # type: () -> None self.start_timestamp = now() self.check_in_id = capture_checkin( - monitor_slug=self.monitor_slug, status=MonitorStatus.IN_PROGRESS + monitor_slug=self.monitor_slug, + status=MonitorStatus.IN_PROGRESS, + monitor_config=self.monitor_config, ) def __exit__(self, exc_type, exc_value, traceback): @@ -72,4 +75,5 @@ def __exit__(self, exc_type, exc_value, traceback): check_in_id=self.check_in_id, status=status, duration=duration_s, + monitor_config=self.monitor_config, ) diff --git a/tests/crons/test_crons.py b/tests/crons/test_crons.py index 0b31494acf..1f50a33751 100644 --- a/tests/crons/test_crons.py +++ b/tests/crons/test_crons.py @@ -33,6 +33,22 @@ def _break_world_contextmanager(name): return "Hello, {}".format(name) +@sentry_sdk.monitor(monitor_slug="ghi789", monitor_config=None) +def _no_monitor_config(): + return + + +@sentry_sdk.monitor( + monitor_slug="ghi789", + monitor_config={ + "schedule": {"type": "crontab", "value": "0 0 * * *"}, + "failure_issue_threshold": 5, + }, +) +def _with_monitor_config(): + return + + def test_decorator(sentry_init): sentry_init() @@ -45,7 +61,9 @@ def test_decorator(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="abc123", status="in_progress"), + mock.call( + monitor_slug="abc123", status="in_progress", monitor_config=None + ), ] ) @@ -70,7 +88,9 @@ def test_decorator_error(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="def456", status="in_progress"), + mock.call( + monitor_slug="def456", status="in_progress", monitor_config=None + ), ] ) @@ -93,7 +113,9 @@ def test_contextmanager(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="abc123", status="in_progress"), + mock.call( + monitor_slug="abc123", status="in_progress", monitor_config=None + ), ] ) @@ -118,7 +140,9 @@ def test_contextmanager_error(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="def456", status="in_progress"), + mock.call( + monitor_slug="def456", status="in_progress", monitor_config=None + ), ] ) @@ -194,6 +218,8 @@ def test_monitor_config(sentry_init, capture_envelopes): monitor_config = { "schedule": {"type": "crontab", "value": "0 0 * * *"}, + "failure_issue_threshold": 5, + "recovery_threshold": 5, } capture_checkin(monitor_slug="abc123", monitor_config=monitor_config) @@ -211,6 +237,41 @@ def test_monitor_config(sentry_init, capture_envelopes): assert "monitor_config" not in check_in +def test_decorator_monitor_config(sentry_init, capture_envelopes): + sentry_init() + envelopes = capture_envelopes() + + _with_monitor_config() + + assert len(envelopes) == 2 + + for check_in_envelope in envelopes: + assert len(check_in_envelope.items) == 1 + check_in = check_in_envelope.items[0].payload.json + + assert check_in["monitor_slug"] == "ghi789" + assert check_in["monitor_config"] == { + "schedule": {"type": "crontab", "value": "0 0 * * *"}, + "failure_issue_threshold": 5, + } + + +def test_decorator_no_monitor_config(sentry_init, capture_envelopes): + sentry_init() + envelopes = capture_envelopes() + + _no_monitor_config() + + assert len(envelopes) == 2 + + for check_in_envelope in envelopes: + assert len(check_in_envelope.items) == 1 + check_in = check_in_envelope.items[0].payload.json + + assert check_in["monitor_slug"] == "ghi789" + assert "monitor_config" not in check_in + + def test_capture_checkin_sdk_not_initialized(): # Tests that the capture_checkin does not raise an error when Sentry SDK is not initialized. # sentry_init() is intentionally omitted. diff --git a/tests/crons/test_crons_async_py3.py b/tests/crons/test_crons_async_py3.py index 6e00b594bd..53ec96d713 100644 --- a/tests/crons/test_crons_async_py3.py +++ b/tests/crons/test_crons_async_py3.py @@ -49,7 +49,9 @@ async def test_decorator(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="abc123", status="in_progress"), + mock.call( + monitor_slug="abc123", status="in_progress", monitor_config=None + ), ] ) @@ -75,7 +77,9 @@ async def test_decorator_error(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="def456", status="in_progress"), + mock.call( + monitor_slug="def456", status="in_progress", monitor_config=None + ), ] ) @@ -99,7 +103,9 @@ async def test_contextmanager(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="abc123", status="in_progress"), + mock.call( + monitor_slug="abc123", status="in_progress", monitor_config=None + ), ] ) @@ -125,7 +131,9 @@ async def test_contextmanager_error(sentry_init): # Check for initial checkin fake_capture_checkin.assert_has_calls( [ - mock.call(monitor_slug="def456", status="in_progress"), + mock.call( + monitor_slug="def456", status="in_progress", monitor_config=None + ), ] )