oncall-engine/engine/apps/alerts/tests/test_default_templates.py

131 lines
4.8 KiB
Python
Raw Permalink Normal View History

import pytest
from jinja2 import TemplateSyntaxError
from apps.alerts.incident_appearance.templaters import (
AlertPhoneCallTemplater,
AlertSlackTemplater,
AlertSmsTemplater,
AlertTelegramTemplater,
AlertWebTemplater,
)
from apps.alerts.models import Alert, AlertReceiveChannel
from common.jinja_templater import jinja_template_env
from common.utils import getattrd
2022-06-13 11:27:41 +03:00
from config_integrations import grafana
@pytest.mark.django_db
Fix warnings when running backend tests (#2079) # What this PR does - update `make test` to always use `settings.ci-test`. Right now it will use whatever the value of `DJANGO_SETTINGS_MODULE` is in `./dev/.env.dev`, which causes ~45 tests to fail - Fix several Python warnings that we see when running the tests ```bash RemovedInDjango40Warning: The providing_args argument is deprecated. As it is purely documentational, it has no replacement. If you rely on this argument as documentation, you can move the text to a code comment or docstring. alert_create_signal = django.dispatch.Signal( ``` ```bash PytestCollectionWarning: cannot collect test class 'TestOnlyBackend' because it has a __init__ constructor (from: apps/api/tests/test_alert_receive_channel_template.py) class TestOnlyBackend(BaseMessagingBackend): ``` ```bash DeprecationWarning: The parameter 'use_aliases' in emoji.emojize() is deprecated and will be removed in version 2.0.0. Use language='alias' instead. To hide this warning, pin/downgrade the package to 'emoji~=1.6.3' return emoji.emojize(self.verbal_name, use_aliases=True) ``` ```bash DateTimeField CustomOnCallShift.start received a naive datetime (2023-06-01 12:53:12) while time zone support is active. warnings.warn("DateTimeField %s received a naive datetime (%s)" ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone /etc/app/apps/twilioapp/tests/test_phone_calls.py:173: DeprecationWarning: The 'text' argument to find()-type methods is deprecated. Use 'string' instead. content = BeautifulSoup(content, features="html.parser").findAll(text=True) ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone apps/twilioapp/tests/test_phone_calls.py::test_wrong_pressed_digit /usr/local/lib/python3.11/site-packages/bs4/builder/__init__.py:545: XMLParsedAsHTMLWarning: It looks like you're parsing an XML document using an HTML parser. If this really is an HTML document (maybe it's XHTML?), you can ignore or filter this warning. If it's XML, you should know that using an XML parser will be more reliable. To parse this document as XML, make sure you have the lxml package installed, and pass the keyword argument `features="xml"` into the BeautifulSoup constructor. ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_forbidden_requests /usr/local/lib/python3.11/site-packages/social_django/urls.py:15: RemovedInDjango40Warning: django.conf.urls.url() is deprecated in favor of django.urls.re_path(). url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth, ``` ```bash apps/twilioapp/tests/test_phone_calls.py: 66 warnings /usr/local/lib/python3.11/site-packages/debug_toolbar/utils.py:255: DeprecationWarning: currentThread() is deprecated, use current_thread() instead thread = threading.currentThread() ``` ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-06-06 20:38:00 +02:00
@pytest.mark.filterwarnings(
"ignore:The input looks more like a filename than markup. You may want to open this file and pass the filehandle into Beautiful Soup."
)
@pytest.mark.parametrize(
"integration, template_module",
# Test only the integrations that have "tests" field in configuration
[
(
integration.slug,
integration,
)
for integration in AlertReceiveChannel._config
if hasattr(integration, "tests")
],
)
def test_default_templates(
make_organization_and_user_with_slack_identities,
make_alert_receive_channel,
make_alert_group,
make_alert,
integration,
template_module,
):
organization, _, _, _ = make_organization_and_user_with_slack_identities()
alert_receive_channel = make_alert_receive_channel(organization, integration=integration)
alert_group = make_alert_group(alert_receive_channel)
alert = make_alert(alert_group=alert_group, raw_request_data=template_module.tests.get("payload"))
slack_templater = AlertSlackTemplater(alert)
web_templater = AlertWebTemplater(alert)
sms_templater = AlertSmsTemplater(alert)
telegram_templater = AlertTelegramTemplater(alert)
phone_call_templater = AlertPhoneCallTemplater(alert)
templaters = {
"slack": slack_templater,
"web": web_templater,
"sms": sms_templater,
"telegram": telegram_templater,
"phone_call": phone_call_templater,
}
for notification_channel, templater in templaters.items():
rendered_alert = templater.render()
for attr in ["title", "message", "image_url"]:
expected = template_module.tests.get(notification_channel).get(attr)
if expected is not None:
expected = expected.format(
web_link=alert.group.web_link, integration_name=alert_receive_channel.verbal_name
)
rendered_attr = getattr(rendered_alert, attr)
assert rendered_attr == expected, (
f"{alert_receive_channel}'s {notification_channel} {attr} " f"is not equal to expected"
)
@pytest.mark.django_db
@pytest.mark.parametrize(
"integration, template_module",
[
(AlertReceiveChannel.INTEGRATION_GRAFANA, grafana),
],
)
def test_render_group_data_templates(
make_organization_and_user_with_slack_identities,
make_alert_receive_channel,
integration,
template_module,
):
organization, _, _, _ = make_organization_and_user_with_slack_identities()
alert_receive_channel = make_alert_receive_channel(organization, integration=integration)
Support alert routing based on labels (#3778) # What this PR does This PR adds support for routing alerts based on labels. https://www.loom.com/share/4401de6e3c4945d5b8961fe43ee373c9 Additionally: - improve the typing around the `get_object` method that is inherited by [`PublicPrimaryKeyMixin.get_object`](https://github.com/grafana/oncall/blob/dev/engine/common/api_helpers/mixins.py#L153) in most of our models. `PublicPrimaryKeyMixin` is generic, so it can be more strongly typed when it is being subclassed, which results in better typing of the `get_object` method in child classes - I decided to do this because I started looking into this task via the [`AlertReceiveChannelView.send_demo_alert` method/endpoint](https://github.com/grafana/oncall/blob/dev/engine/apps/api/views/alert_receive_channel.py#L242). Within that method, `instance` is not typed because the inherited `get_object` method is not typed.. I digress 😄 - improve typing around `Alert.create` and `apps.integrations.tasks.create_alert` functions - make `Alert.render_group_data` more DRY by extracting some logic out into `Alert._apply_jinja_template_to_alert_payload_and_labels` - deduplicate the logic of `value.strip().lower() in ["1", "true", "ok"]` into a shared function, `common.jinja_templater.apply_jinja_template.templated_value_is_truthy` Closes https://github.com/grafana/oncall-private/issues/2490 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) - [x] Documentation added (or `pr:no public docs` PR label added if not required) (will be done in #3762)
2024-01-30 13:07:19 -05:00
group_data = Alert.render_group_data(alert_receive_channel, template_module.tests.get("payload"), {})
assert group_data.group_distinction == template_module.tests.get("group_distinction")
assert group_data.is_resolve_signal == template_module.tests.get("is_resolve_signal")
assert group_data.is_acknowledge_signal == template_module.tests.get("is_acknowledge_signal")
def test_default_templates_are_valid():
template_names = AlertReceiveChannel.template_names
for integration in AlertReceiveChannel._config:
for template_name in template_names:
template = getattrd(integration, f"{template_name}", None)
if template is not None:
try:
jinja_template_env.from_string(template)
except TemplateSyntaxError as e:
pytest.fail(e.message)
@pytest.mark.parametrize("config", AlertReceiveChannel._config)
def test_is_demo_alert_enabled(config):
# is_demo_alert_enabled must be defined
try:
assert isinstance(config.is_demo_alert_enabled, bool), "is_demo_alert_enabled must be bool"
except AttributeError:
pytest.fail("is_demo_alert_enabled must be defined")
# example_payload must be defined
try:
assert config.example_payload is None or isinstance(
config.example_payload, dict
), "example_payload must be dict or None"
except AttributeError:
pytest.fail("example_payload must be defined")
# example_payload must be provided when is_demo_alert_enabled is True
if config.is_demo_alert_enabled:
assert config.example_payload, "example_payload must be defined and non-empty"
else:
assert config.example_payload is None, "example_payload must be None if is_demo_alert_enabled is False"