Skip to content

Commit ff38d31

Browse files
committed
restore tests
1 parent 5a886e9 commit ff38d31

File tree

1 file changed

+269
-1
lines changed

1 file changed

+269
-1
lines changed

tests/sentry/monitors/test_models.py

Lines changed: 269 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,281 @@
1+
from datetime import datetime, timezone
12
from unittest import mock
23

34
import pytest
5+
from django.conf import settings
6+
from django.test.utils import override_settings
47

5-
from sentry.monitors.models import CronMonitorDataSourceHandler, Monitor
8+
from sentry.monitors.models import (
9+
CronMonitorDataSourceHandler,
10+
Monitor,
11+
MonitorEnvironment,
12+
MonitorEnvironmentLimitsExceeded,
13+
MonitorLimitsExceeded,
14+
ScheduleType,
15+
)
616
from sentry.monitors.types import DATA_SOURCE_CRON_MONITOR
17+
from sentry.monitors.validators import ConfigValidator
718
from sentry.testutils.cases import TestCase
819
from sentry.workflow_engine.models import DataSource
920

1021

22+
class MonitorTestCase(TestCase):
23+
def test_next_run_crontab(self) -> None:
24+
ts = datetime(2019, 1, 1, 1, 10, 20, tzinfo=timezone.utc)
25+
monitor = Monitor(
26+
config={
27+
"schedule_type": ScheduleType.CRONTAB,
28+
"schedule": "* * * * *",
29+
"checkin_margin": None,
30+
"max_runtime": None,
31+
}
32+
)
33+
monitor_environment = MonitorEnvironment(monitor=monitor, last_checkin=ts)
34+
35+
# XXX: Seconds are removed as we clamp to the minute
36+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
37+
2019, 1, 1, 1, 11, tzinfo=timezone.utc
38+
)
39+
assert monitor_environment.monitor.get_next_expected_checkin_latest(ts) == datetime(
40+
2019, 1, 1, 1, 12, tzinfo=timezone.utc
41+
)
42+
43+
monitor.config["schedule"] = "*/5 * * * *"
44+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
45+
2019, 1, 1, 1, 15, tzinfo=timezone.utc
46+
)
47+
assert monitor_environment.monitor.get_next_expected_checkin_latest(ts) == datetime(
48+
2019, 1, 1, 1, 16, tzinfo=timezone.utc
49+
)
50+
51+
def test_next_run_latest_crontab_with_margin(self) -> None:
52+
ts = datetime(2019, 1, 1, 1, 10, 20, tzinfo=timezone.utc)
53+
monitor = Monitor(
54+
config={
55+
"schedule_type": ScheduleType.CRONTAB,
56+
"schedule": "* * * * *",
57+
"checkin_margin": 5,
58+
"max_runtime": None,
59+
}
60+
)
61+
monitor_environment = MonitorEnvironment(monitor=monitor, last_checkin=ts)
62+
63+
# XXX: Seconds are removed as we clamp to the minute
64+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
65+
2019, 1, 1, 1, 11, tzinfo=timezone.utc
66+
)
67+
assert monitor_environment.monitor.get_next_expected_checkin_latest(ts) == datetime(
68+
2019, 1, 1, 1, 16, tzinfo=timezone.utc
69+
)
70+
71+
def test_next_run_crontab_with_timezone(self) -> None:
72+
ts = datetime(2019, 1, 1, 1, 10, 20, tzinfo=timezone.utc)
73+
monitor = Monitor(
74+
config={
75+
"schedule_type": ScheduleType.CRONTAB,
76+
"schedule": "0 12 * * *",
77+
"timezone": "UTC",
78+
"checkin_margin": None,
79+
"max_runtime": None,
80+
},
81+
)
82+
monitor_environment = MonitorEnvironment(monitor=monitor, last_checkin=ts)
83+
84+
# XXX: Seconds are removed as we clamp to the minute
85+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
86+
2019, 1, 1, 12, 00, tzinfo=timezone.utc
87+
)
88+
89+
# Europe/Berlin == UTC+01:00.
90+
# the run should be represented 1 hours earlier in UTC time
91+
monitor.config["timezone"] = "Europe/Berlin"
92+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
93+
2019, 1, 1, 11, 00, tzinfo=timezone.utc
94+
)
95+
96+
def test_next_run_interval(self) -> None:
97+
ts = datetime(2019, 1, 1, 1, 10, 20, tzinfo=timezone.utc)
98+
monitor = Monitor(
99+
config={
100+
"schedule": [1, "month"],
101+
"schedule_type": ScheduleType.INTERVAL,
102+
"checkin_margin": None,
103+
"max_runtime": None,
104+
},
105+
)
106+
monitor_environment = MonitorEnvironment(monitor=monitor, last_checkin=ts)
107+
108+
# XXX: Seconds are removed as we clamp to the minute.
109+
assert monitor_environment.monitor.get_next_expected_checkin(ts) == datetime(
110+
2019, 2, 1, 1, 10, 0, tzinfo=timezone.utc
111+
)
112+
113+
def test_save_defaults_slug_to_name(self) -> None:
114+
monitor = Monitor.objects.create(
115+
organization_id=self.organization.id,
116+
project_id=self.project.id,
117+
name="My Awesome Monitor",
118+
config={
119+
"schedule": [1, "month"],
120+
"schedule_type": ScheduleType.INTERVAL,
121+
"checkin_margin": None,
122+
"max_runtime": None,
123+
},
124+
)
125+
126+
assert monitor.slug == "my-awesome-monitor"
127+
128+
def test_save_defaults_slug_unique(self) -> None:
129+
monitor = Monitor.objects.create(
130+
organization_id=self.organization.id,
131+
project_id=self.project.id,
132+
name="My Awesome Monitor",
133+
slug="my-awesome-monitor",
134+
config={
135+
"schedule": [1, "month"],
136+
"schedule_type": ScheduleType.INTERVAL,
137+
"checkin_margin": None,
138+
"max_runtime": None,
139+
},
140+
)
141+
142+
assert monitor.slug == "my-awesome-monitor"
143+
144+
# Create another monitor with the same name
145+
monitor = Monitor.objects.create(
146+
organization_id=self.organization.id,
147+
project_id=self.project.id,
148+
name="My Awesome Monitor",
149+
config={
150+
"schedule": [1, "month"],
151+
"schedule_type": ScheduleType.INTERVAL,
152+
"checkin_margin": None,
153+
"max_runtime": None,
154+
},
155+
)
156+
157+
assert monitor.slug.startswith("my-awesome-monitor-")
158+
159+
@override_settings(MAX_MONITORS_PER_ORG=2)
160+
def test_monitor_organization_limit(self) -> None:
161+
for i in range(settings.MAX_MONITORS_PER_ORG):
162+
Monitor.objects.create(
163+
organization_id=self.organization.id,
164+
project_id=self.project.id,
165+
name=f"Unicron-{i}",
166+
slug=f"unicron-{i}",
167+
config={
168+
"schedule": [1, "month"],
169+
"schedule_type": ScheduleType.INTERVAL,
170+
"checkin_margin": None,
171+
"max_runtime": None,
172+
},
173+
)
174+
175+
with pytest.raises(
176+
MonitorLimitsExceeded,
177+
match=f"You may not exceed {settings.MAX_MONITORS_PER_ORG} monitors per organization",
178+
):
179+
Monitor.objects.create(
180+
organization_id=self.organization.id,
181+
project_id=self.project.id,
182+
name=f"Unicron-{settings.MAX_MONITORS_PER_ORG}",
183+
slug=f"unicron-{settings.MAX_MONITORS_PER_ORG}",
184+
config={
185+
"schedule": [1, "month"],
186+
"schedule_type": ScheduleType.INTERVAL,
187+
"checkin_margin": None,
188+
"max_runtime": None,
189+
},
190+
)
191+
192+
193+
class MonitorEnvironmentTestCase(TestCase):
194+
@override_settings(MAX_ENVIRONMENTS_PER_MONITOR=2)
195+
def test_monitor_environment_limits(self) -> None:
196+
monitor = Monitor.objects.create(
197+
organization_id=self.organization.id,
198+
project_id=self.project.id,
199+
name="Unicron",
200+
slug="unicron",
201+
config={
202+
"schedule": [1, "month"],
203+
"schedule_type": ScheduleType.INTERVAL,
204+
"checkin_margin": None,
205+
"max_runtime": None,
206+
},
207+
)
208+
209+
for i in range(settings.MAX_ENVIRONMENTS_PER_MONITOR):
210+
MonitorEnvironment.objects.ensure_environment(self.project, monitor, f"space-{i}")
211+
212+
with pytest.raises(
213+
MonitorEnvironmentLimitsExceeded,
214+
match=f"You may not exceed {settings.MAX_ENVIRONMENTS_PER_MONITOR} environments per monitor",
215+
):
216+
MonitorEnvironment.objects.ensure_environment(
217+
self.project, monitor, f"space-{settings.MAX_ENVIRONMENTS_PER_MONITOR}"
218+
)
219+
220+
def test_update_config(self) -> None:
221+
monitor = Monitor.objects.create(
222+
organization_id=self.organization.id,
223+
project_id=self.project.id,
224+
name="Unicron",
225+
slug="unicron",
226+
config={
227+
"schedule": [1, "month"],
228+
"schedule_type": ScheduleType.INTERVAL,
229+
"alert_rule_id": 1,
230+
"checkin_margin": None,
231+
"max_runtime": None,
232+
},
233+
)
234+
235+
new_config = {
236+
"schedule": {
237+
"type": "crontab",
238+
"value": "0 0 1 2 *",
239+
},
240+
"max_runtime": 10,
241+
"garbage": "data",
242+
}
243+
validator = ConfigValidator(data=new_config)
244+
assert validator.is_valid()
245+
validated_config = validator.validated_data
246+
monitor.update_config(new_config, validated_config)
247+
248+
assert monitor.config == {
249+
"schedule": "0 0 1 2 *",
250+
"schedule_type": ScheduleType.CRONTAB,
251+
"checkin_margin": None,
252+
"max_runtime": 10,
253+
"alert_rule_id": 1,
254+
}
255+
256+
def test_config_validator(self) -> None:
257+
monitor = Monitor.objects.create(
258+
organization_id=self.organization.id,
259+
project_id=self.project.id,
260+
name="Unicron",
261+
slug="unicron",
262+
config={
263+
"checkin_margin": None,
264+
"max_runtime": None,
265+
"schedule": [1, "month"],
266+
"schedule_type": ScheduleType.INTERVAL,
267+
"alert_rule_id": 1,
268+
},
269+
)
270+
validated_config = monitor.get_validated_config()
271+
assert validated_config is not None
272+
273+
# Check to make sure bad config fails validation
274+
validated_config["bad_key"] = 100
275+
monitor.config = validated_config
276+
assert monitor.get_validated_config() is None
277+
278+
11279
class CronMonitorDataSourceHandlerTest(TestCase):
12280
def setUp(self):
13281
super().setUp()

0 commit comments

Comments
 (0)