This PR add labels for webhooks.
1. Make webhook "labelable" with ability to filter by labels.
2. Add labels to the webhook payload. It contain new field webhook with
it's name, id and labels. Field integration and alert_group has a
corresponding label field as well. See example of a new payload below:
```
{
"event": {
"type": "escalation"
},
"user": null,
"alert_group": {
"id": "IRFN6ZD31N31B",
"integration_id": "CTWM7U4A2QG97",
"route_id": "RUE7U7Z46SKGY",
"alerts_count": 1,
"state": "firing",
"created_at": "2023-11-22T08:54:55.178243Z",
"resolved_at": null,
"acknowledged_at": null,
"title": "Incident",
"permalinks": {
"slack": null,
"telegram": null,
"web": "http://grafana:3000/a/grafana-oncall-app/alert-groups/IRFN6ZD31N31B"
},
"labels": {
"severity": "critical"
}
},
"alert_group_id": "IRFN6ZD31N31B",
"alert_payload": {
"message": "This alert was sent by user for demonstration purposes"
},
"integration": {
"id": "CTWM7U4A2QG97",
"type": "webhook",
"name": "hi - Webhook",
"team": null,
"labels": {
"hello": "world",
"severity": "critical"
}
},
"notified_users": [],
"users_to_be_notified": [],
"webhook": {
"id": "WHAXK4BTC7TAEQ",
"name": "test",
"labels": {
"hello": "kesha"
}
}
}
```
I feel that there is an opportunity to make code cleaner - remove all
label logic from serializers, views and utils to models or dedicated
LabelerService and introduce Labelable interface with something like
label_verbal, update_labels methods. However, I don't want to tie
webhook labels with a refactoring.
---------
Co-authored-by: Dominik <dominik.broj@grafana.com>
336 lines
14 KiB
Python
336 lines
14 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
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
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.get_keys",
|
|
return_value=([{"name": "team", "id": "keyid123"}], {"status_code": status.HTTP_200_OK}),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_labels_get_keys(
|
|
mocked_get_labels_keys,
|
|
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()
|
|
client = APIClient()
|
|
url = reverse("api-internal:get_keys")
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
expected_result = [{"name": "team", "id": "keyid123"}]
|
|
|
|
assert mocked_get_labels_keys.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.get_values",
|
|
return_value=(
|
|
{"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]},
|
|
{"status_code": status.HTTP_200_OK},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_get_update_key_get(
|
|
mocked_get_values,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
expected_result = {"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]}
|
|
|
|
assert mocked_get_values.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.rename_key",
|
|
return_value=(
|
|
{"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]},
|
|
{"status_code": status.HTTP_200_OK},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_get_update_key_put(
|
|
mocked_rename_key,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
data = {"name": "team"}
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data=data)
|
|
expected_result = {"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]}
|
|
|
|
assert mocked_rename_key.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.add_value",
|
|
return_value=(
|
|
{"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]},
|
|
{"status_code": status.HTTP_200_OK},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_add_value(
|
|
mocked_add_value,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:add_value", kwargs={"key_id": "keyid123"})
|
|
data = {"name": "yolo"}
|
|
response = client.post(url, format="json", **make_user_auth_headers(user, token), data=data)
|
|
expected_result = {"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]}
|
|
|
|
assert mocked_add_value.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.rename_value",
|
|
return_value=(
|
|
{"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]},
|
|
{"status_code": status.HTTP_200_OK},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_rename_value(
|
|
mocked_rename_value,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
data = {"name": "yolo"}
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data=data)
|
|
expected_result = {"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]}
|
|
|
|
assert mocked_rename_value.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.get_value",
|
|
return_value=(
|
|
{"id": "valueid123", "name": "yolo"},
|
|
{"status_code": status.HTTP_200_OK},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_get_value(
|
|
mocked_get_value,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
expected_result = {"id": "valueid123", "name": "yolo"}
|
|
|
|
assert mocked_get_value.called
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@patch(
|
|
"apps.labels.client.LabelsAPIClient.create_label",
|
|
return_value=(
|
|
{"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]},
|
|
{"status_code": status.HTTP_201_CREATED},
|
|
),
|
|
)
|
|
@pytest.mark.django_db
|
|
def test_labels_create_label(
|
|
mocked_create_label,
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
url = reverse("api-internal:create_label")
|
|
data = {"key": {"name": "team"}, "values": [{"name": "yolo"}]}
|
|
expected_result = {"key": {"id": "keyid123", "name": "team"}, "values": [{"id": "valueid123", "name": "yolo"}]}
|
|
response = client.post(url, format="json", data=data, **make_user_auth_headers(user, token))
|
|
|
|
assert mocked_create_label.called
|
|
assert response.status_code == status.HTTP_201_CREATED
|
|
assert response.json() == expected_result
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_labels_feature_false(
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
settings,
|
|
):
|
|
setattr(settings, "FEATURE_LABELS_ENABLED_FOR_ALL", False)
|
|
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
client = APIClient()
|
|
|
|
url = reverse("api-internal:get_keys")
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:add_value", kwargs={"key_id": "keyid123"})
|
|
response = client.post(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
url = reverse("api-internal:create_label")
|
|
response = client.post(url, format="json", data={}, **make_user_auth_headers(user, token))
|
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
|
|
|
|
|
@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_labels_permissions_get_actions(
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
role,
|
|
expected_status,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
|
client = APIClient()
|
|
with patch("apps.api.views.labels.LabelsViewSet.get_keys", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:get_keys")
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
assert response.status_code == expected_status
|
|
|
|
with patch("apps.api.views.labels.LabelsViewSet.get_key", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
assert response.status_code == expected_status
|
|
|
|
with patch("apps.api.views.labels.LabelsViewSet.get_value", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
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_403_FORBIDDEN),
|
|
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
|
],
|
|
)
|
|
def test_labels_permissions_create_update_actions(
|
|
make_organization_and_user_with_plugin_token,
|
|
make_user_auth_headers,
|
|
role,
|
|
expected_status,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
|
client = APIClient()
|
|
with patch("apps.api.views.labels.LabelsViewSet.rename_key", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:get_update_key", kwargs={"key_id": "keyid123"})
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == expected_status
|
|
|
|
with patch("apps.api.views.labels.LabelsViewSet.add_value", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:add_value", kwargs={"key_id": "keyid123"})
|
|
response = client.post(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == expected_status
|
|
|
|
with patch("apps.api.views.labels.LabelsViewSet.rename_value", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:get_update_value", kwargs={"key_id": "keyid123", "value_id": "valueid123"})
|
|
response = client.put(url, format="json", **make_user_auth_headers(user, token), data={})
|
|
assert response.status_code == expected_status
|
|
|
|
with patch("apps.api.views.labels.LabelsViewSet.create_label", return_value=Response(status=status.HTTP_200_OK)):
|
|
url = reverse("api-internal:create_label")
|
|
response = client.post(url, format="json", data={}, **make_user_auth_headers(user, token))
|
|
assert response.status_code == expected_status
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_alert_group_labels_get_keys(
|
|
make_organization_and_user_with_plugin_token,
|
|
make_alert_receive_channel,
|
|
make_alert_group,
|
|
make_alert_group_label_association,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
|
|
alert_receive_channel = make_alert_receive_channel(user.organization)
|
|
alert_group = make_alert_group(alert_receive_channel)
|
|
make_alert_group_label_association(organization, alert_group, key_name="a", value_name="b")
|
|
|
|
client = APIClient()
|
|
url = reverse("api-internal:alert_group_labels-get_keys")
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == [{"id": "a", "name": "a"}]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_alert_group_labels_get_key(
|
|
make_organization_and_user_with_plugin_token,
|
|
make_alert_receive_channel,
|
|
make_alert_group,
|
|
make_alert_group_label_association,
|
|
make_user_auth_headers,
|
|
):
|
|
organization, user, token = make_organization_and_user_with_plugin_token()
|
|
|
|
alert_receive_channel = make_alert_receive_channel(user.organization)
|
|
alert_group = make_alert_group(alert_receive_channel)
|
|
make_alert_group_label_association(organization, alert_group, key_name="a", value_name="b")
|
|
|
|
client = APIClient()
|
|
url = reverse("api-internal:alert_group_labels-get_key", kwargs={"key_id": "a"})
|
|
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
|
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() == {"key": {"id": "a", "name": "a"}, "values": [{"id": "b", "name": "b"}]}
|