oncall-engine/engine/apps/api/tests/test_alert_receive_channel_template.py
Innokentii Konstantinov 36d2c3bdb7
Adds new templates cheatsheats (#3643)
Co-authored-by: Maxim Mordasov <maxim.mordasov@grafana.com>
2024-01-17 13:49:36 +00:00

499 lines
19 KiB
Python

from unittest.mock import patch
import pytest
from django.test.utils import override_settings
from django.urls import reverse
from rest_framework import status
from rest_framework.response import Response
from rest_framework.test import APIClient
from apps.api.permissions import LegacyAccessControlRole
from apps.base.messaging import BaseMessagingBackend
from apps.base.tests.messaging_backend import TestOnlyBackend
@pytest.mark.django_db
@pytest.mark.parametrize(
"role,expected_status",
[
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
(LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN),
(LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN),
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
],
)
def test_alert_receive_channel_template_update_permissions(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
role,
expected_status,
):
organization, user, token = make_organization_and_user_with_plugin_token(role=role)
alert_receive_channel = make_alert_receive_channel(organization)
client = APIClient()
url = reverse("api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.pk})
with patch(
"apps.api.views.alert_receive_channel_template.AlertReceiveChannelTemplateView.update",
return_value=Response(
status=status.HTTP_200_OK,
),
):
response = client.put(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == expected_status
response = client.patch(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == expected_status
@pytest.mark.django_db
@pytest.mark.parametrize(
"role,expected_status",
[
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
(LegacyAccessControlRole.EDITOR, status.HTTP_200_OK),
(LegacyAccessControlRole.VIEWER, status.HTTP_200_OK),
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
],
)
def test_alert_receive_channel_template_detail_permissions(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
role,
expected_status,
):
organization, user, token = make_organization_and_user_with_plugin_token(role=role)
alert_receive_channel = make_alert_receive_channel(organization)
client = APIClient()
url = reverse("api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.pk})
with patch(
"apps.api.views.alert_receive_channel_template.AlertReceiveChannelTemplateView.retrieve",
return_value=Response(
status=status.HTTP_200_OK,
),
):
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == expected_status
@pytest.mark.django_db
def test_alert_receive_channel_template_include_additional_backend_templates(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(
organization,
messaging_backends_templates={"TESTONLY": {"title": "the-title", "message": "the-message", "image_url": "url"}},
)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
templates_data = response.json()
assert templates_data["testonly_title_template"] == "the-title"
assert templates_data["testonly_message_template"] == "the-message"
assert templates_data["testonly_image_url_template"] == "url"
@pytest.mark.django_db
def test_alert_receive_channel_template_include_additional_backend_templates_using_defaults(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization, messaging_backends_templates=None)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
templates_data = response.json()
assert templates_data["testonly_title_template"] == alert_receive_channel.get_default_template_attribute(
"TESTONLY", "title"
)
assert templates_data["testonly_message_template"] == alert_receive_channel.get_default_template_attribute(
"TESTONLY", "message"
)
assert templates_data["testonly_image_url_template"] == alert_receive_channel.get_default_template_attribute(
"TESTONLY", "image_url"
)
@pytest.mark.django_db
def test_update_alert_receive_channel_backend_template_invalid_template(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization, messaging_backends_templates=None)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
response = client.put(
url, format="json", data={"testonly_title_template": "{{ wrong"}, **make_user_auth_headers(user, token)
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json() == {"testonly_title_template": "invalid template"}
@pytest.mark.django_db
def test_update_alert_receive_channel_backend_template_set_default_template(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
# create alert_receive_channel with non-default values for TESTONLY messaging backend templates
testonly_templates = {"TESTONLY": {"title": "non-default", "message": "non-default", "image_url": "non-default"}}
alert_receive_channel = make_alert_receive_channel(organization, messaging_backends_templates=testonly_templates)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
# update templates with empty string, which mean templates are default
response = client.put(
url,
format="json",
data={"testonly_title_template": "", "testonly_message_template": "", "testonly_image_url_template": ""},
**make_user_auth_headers(user, token),
)
assert response.status_code == status.HTTP_200_OK
alert_receive_channel.refresh_from_db()
assert alert_receive_channel.messaging_backends_templates["TESTONLY"] == {
"title": "",
"message": "",
"image_url": "",
}
# check if internal api returns default values
response = client.get(
url,
format="json",
**make_user_auth_headers(user, token),
)
assert response.status_code == status.HTTP_200_OK
# WEB_TEMPLATE is default for templates from messaging backends
default_title = alert_receive_channel.INTEGRATION_TO_DEFAULT_WEB_TITLE_TEMPLATE[alert_receive_channel.integration]
default_message = alert_receive_channel.INTEGRATION_TO_DEFAULT_WEB_MESSAGE_TEMPLATE[
alert_receive_channel.integration
]
default_image_url = alert_receive_channel.INTEGRATION_TO_DEFAULT_WEB_IMAGE_URL_TEMPLATE[
alert_receive_channel.integration
]
assert response.json()["testonly_title_template"] == default_title
assert response.json()["testonly_message_template"] == default_message
assert response.json()["testonly_image_url_template"] == default_image_url
@pytest.mark.django_db
def test_update_alert_receive_channel_legacy_template_set_default_template(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization, messaging_backends_templates=None)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
# set non-default templates
alert_receive_channel.slack_title_template = "non-default-template"
alert_receive_channel.slack_message_template = "non-default-template"
alert_receive_channel.slack_image_url_template = "non-default-template"
alert_receive_channel.save()
# update templates with empty string, which mean templates are default
response = client.put(
url,
format="json",
data={"slack_title_template": "", "slack_message_template": "", "slack_image_url_template": ""},
**make_user_auth_headers(user, token),
)
assert response.status_code == status.HTTP_200_OK
alert_receive_channel.refresh_from_db()
assert alert_receive_channel.slack_title_template == ""
assert alert_receive_channel.slack_message_template == ""
assert alert_receive_channel.slack_image_url_template == ""
# check if internal api returns default values
response = client.get(
url,
format="json",
**make_user_auth_headers(user, token),
)
assert response.status_code == status.HTTP_200_OK
default_title = alert_receive_channel.INTEGRATION_TO_DEFAULT_SLACK_TITLE_TEMPLATE[alert_receive_channel.integration]
default_message = alert_receive_channel.INTEGRATION_TO_DEFAULT_SLACK_MESSAGE_TEMPLATE[
alert_receive_channel.integration
]
default_image_url = alert_receive_channel.INTEGRATION_TO_DEFAULT_SLACK_IMAGE_URL_TEMPLATE[
alert_receive_channel.integration
]
assert response.json()["slack_title_template"] == default_title
assert response.json()["slack_message_template"] == default_message
assert response.json()["slack_image_url_template"] == default_image_url
@pytest.mark.django_db
def test_update_alert_receive_channel_backend_template_update_values(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(
organization,
messaging_backends_templates={
"TESTONLY": {"title": "the-title", "message": "some-message"},
"OTHER": {"title": "some-title"},
},
)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
# patch messaging backends to add OTHER as a valid backend
with patch(
"apps.api.serializers.alert_receive_channel.get_messaging_backends",
return_value=[("TESTONLY", TestOnlyBackend()), ("OTHER", BaseMessagingBackend())],
):
response = client.put(
url, format="json", data={"testonly_title_template": "updated-title"}, **make_user_auth_headers(user, token)
)
assert response.status_code == status.HTTP_200_OK
alert_receive_channel.refresh_from_db()
assert alert_receive_channel.messaging_backends_templates["TESTONLY"] == {
"title": "updated-title",
"message": "some-message",
}
assert alert_receive_channel.messaging_backends_templates["OTHER"] == {"title": "some-title"}
@pytest.mark.django_db
def test_preview_alert_receive_channel_backend_templater(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
make_channel_filter,
make_alert_group,
make_alert,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization)
default_channel_filter = make_channel_filter(alert_receive_channel, is_default=True)
alert_group = make_alert_group(alert_receive_channel, channel_filter=default_channel_filter)
make_alert(alert_group=alert_group, raw_request_data={"title": "alert!"})
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel-preview-template", kwargs={"pk": alert_receive_channel.public_primary_key}
)
data = {
"template_body": "title: {{ payload.title }}",
"template_name": "testonly_title_template",
}
response = client.post(url, format="json", data=data, **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
assert response.json() == {"preview": "title: alert!", "is_valid_json_object": False}
@pytest.mark.django_db
def test_alert_receive_channel_template_is_valid_json_check(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
make_channel_filter,
make_alert_group,
make_alert,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization)
default_channel_filter = make_channel_filter(alert_receive_channel, is_default=True)
alert_group = make_alert_group(alert_receive_channel, channel_filter=default_channel_filter)
make_alert(alert_group=alert_group, raw_request_data={"title": "alert!"})
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel-preview-template", kwargs={"pk": alert_receive_channel.public_primary_key}
)
# template which should produce valid json string
data = {
"template_body": "{{ payload | tojson }}",
"template_name": "alert_group_multi_label",
}
response = client.post(url, format="json", data=data, **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
assert response.json()["is_valid_json_object"] is True
# template which produce not avalid json string
data = {
"template_body": "{{ payload.title }}",
"template_name": "alert_group_multi_label",
}
response = client.post(url, format="json", data=data, **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
assert response.json()["is_valid_json_object"] is False
@pytest.mark.django_db
def test_preview_alert_group_labels(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
make_channel_filter,
make_alert_group,
make_alert,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization)
default_channel_filter = make_channel_filter(alert_receive_channel, is_default=True)
alert_group = make_alert_group(alert_receive_channel, channel_filter=default_channel_filter)
make_alert(alert_group=alert_group, raw_request_data={"labels": {"1": "2"}})
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel-preview-template",
kwargs={"pk": alert_receive_channel.public_primary_key},
)
data = {
"template_body": "{{ payload.labels | tojson }}",
"template_name": "alert_group_multi_label",
}
response = client.post(url, format="json", data=data, **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
assert response.json() == {"preview": '{"1": "2"}', "is_valid_json_object": True}
@pytest.mark.django_db
def test_update_alert_receive_channel_templates(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
def template_update_func(template):
return f"{template}_updated"
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(
organization,
messaging_backends_templates={"TESTONLY": {"title": "the-title", "message": "the-message", "image_url": "url"}},
)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
# Get response from templates endpoint to get initial templates data
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
existing_templates_data = response.json()
# build data for PUT request from data we received
# leave only templates-related fields
del existing_templates_data["id"]
del existing_templates_data["verbal_name"]
del existing_templates_data["payload_example"]
del existing_templates_data["is_based_on_alertmanager"]
# update each template
new_templates_data = {}
for template_name, template_value in existing_templates_data.items():
new_templates_data[template_name] = template_update_func(template_value)
response = client.put(url, format="json", data=new_templates_data, **make_user_auth_headers(user, token))
# check if updated templates are applied
updated_templates_data = response.json()
for template_name, prev_template_value in existing_templates_data.items():
if template_name.endswith("_is_default"):
assert updated_templates_data[template_name] is False
else:
assert updated_templates_data[template_name] == template_update_func(prev_template_value)
@override_settings(FEATURE_TELEGRAM_INTEGRATION_ENABLED=False)
@override_settings(FEATURE_SLACK_INTEGRATION_ENABLED=False)
@pytest.mark.django_db
def test_update_alert_receive_channel_backend_template_hide_disabled_integration_templates(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
slack_integration_required_templates = [
"slack_title_template",
"slack_message_template",
"slack_image_url_template",
]
telegram_integration_required_templates = [
"telegram_title_template",
"telegram_message_template",
"telegram_image_url_template",
]
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(
organization,
messaging_backends_templates={"TESTONLY": {"title": "the-title", "message": "the-message", "image_url": "url"}},
)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel_template-detail", kwargs={"pk": alert_receive_channel.public_primary_key}
)
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
templates_data = response.json()
for st in slack_integration_required_templates:
assert st not in templates_data
for tt in telegram_integration_required_templates:
assert tt not in templates_data