oncall-engine/engine/apps/public_api/tests/test_webhooks.py
Michael Derynck 2f1cc43b0e
Fix public actions endpoint to handle empty user field (#3053)
# What this PR does
Fixes a regression that was introduced when actions were remapped to new
webhooks. Validation in the serializer was making the user field no
longer accept blank and None values. This PR makes those values accepted
again.

## Which issue(s) this PR fixes
https://github.com/grafana/terraform-provider-grafana/issues/1025

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
2023-09-26 14:54:41 +00:00

359 lines
12 KiB
Python

import json
import pytest
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
from apps.webhooks.models import Webhook
def _get_expected_result(webhook):
return {
"id": webhook.public_primary_key,
"name": webhook.name,
"team": webhook.team,
"url": webhook.url,
"data": webhook.data,
"username": webhook.username,
"password": webhook.password,
"authorization_header": webhook.authorization_header,
"forward_all": webhook.forward_all,
"is_webhook_enabled": webhook.is_webhook_enabled,
"trigger_template": webhook.trigger_template,
"headers": webhook.headers,
"http_method": webhook.http_method,
"trigger_type": Webhook.PUBLIC_TRIGGER_TYPES_MAP[webhook.trigger_type],
"integration_filter": webhook.integration_filter,
}
@pytest.mark.django_db
def test_get_webhooks(make_organization_and_user_with_token, make_custom_webhook):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-list")
response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}")
expected_payload = {
"count": 1,
"next": None,
"previous": None,
"results": [_get_expected_result(webhook)],
"current_page_number": 1,
"page_size": 50,
"total_pages": 1,
}
assert response.status_code == status.HTTP_200_OK
assert response.data == expected_payload
@pytest.mark.django_db
def test_get_webhooks_filter_by_name(
make_organization_and_user_with_token,
make_custom_webhook,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-list")
response = client.get(f"{url}?name={webhook.name}", format="json", HTTP_AUTHORIZATION=f"{token}")
expected_payload = {
"count": 1,
"next": None,
"previous": None,
"results": [_get_expected_result(webhook)],
"current_page_number": 1,
"page_size": 50,
"total_pages": 1,
}
assert response.status_code == status.HTTP_200_OK
assert response.data == expected_payload
@pytest.mark.django_db
def test_get_webhooks_filter_by_name_empty_result(
make_organization_and_user_with_token,
make_custom_webhook,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-list")
response = client.get(f"{url}?name=NonExistentName", format="json", HTTP_AUTHORIZATION=f"{token}")
expected_payload = {
"count": 0,
"next": None,
"previous": None,
"results": [],
"current_page_number": 1,
"page_size": 50,
"total_pages": 1,
}
assert response.status_code == status.HTTP_200_OK
assert response.data == expected_payload
@pytest.mark.django_db
def test_get_webhook(
make_organization_and_user_with_token,
make_custom_webhook,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-detail", kwargs={"pk": webhook.public_primary_key})
response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}")
expected_payload = _get_expected_result(webhook)
assert response.status_code == status.HTTP_200_OK
assert response.data == expected_payload
@pytest.mark.django_db
def test_create_webhook(make_organization_and_user_with_token):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
url = reverse("api-public:webhooks-list")
data = {}
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
data["name"] = "Test outgoing webhook"
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
data["url"] = "https://example.com"
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
data["trigger_type"] = "escalation"
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
data["http_method"] = "POST"
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_201_CREATED
webhook = Webhook.objects.get(public_primary_key=response.data["id"])
expected_result = _get_expected_result(webhook)
assert response.data == expected_result
@pytest.mark.django_db
@pytest.mark.parametrize(
"optional_value",
[
None,
"",
],
)
def test_create_webhook_optional_fields(make_organization_and_user_with_token, optional_value):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
url = reverse("api-public:webhooks-list")
data = {
"name": "Test outgoing webhook with nested data",
"url": "https://example.com",
"http_method": "POST",
"trigger_type": "acknowledge",
"data": optional_value,
"username": optional_value,
"password": optional_value,
"authorization_header": optional_value,
"trigger_template": optional_value,
"headers": optional_value,
"forward_all": True,
"is_webhook_enabled": True,
"integration_filter": optional_value,
}
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook = Webhook.objects.get(public_primary_key=response.data["id"])
expected_result = _get_expected_result(webhook)
assert response.status_code == status.HTTP_201_CREATED
assert response.json() == expected_result
@pytest.mark.django_db
def test_create_webhook_nested_data(make_organization_and_user_with_token):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
url = reverse("api-public:webhooks-list")
data = {
"name": "Test outgoing webhook with nested data",
"url": "https://example.com",
"data": '{"nested_item": "{{ alert_payload.foo.bar | to_json }}"}',
"http_method": "POST",
"trigger_type": "acknowledge",
}
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
data["data"] = '{"nested_item": "{{ alert_payload.foo.bar | tojson() }}"}'
response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook = Webhook.objects.get(public_primary_key=response.data["id"])
expected_result = _get_expected_result(webhook)
assert response.status_code == status.HTTP_201_CREATED
assert response.json() == expected_result
@pytest.mark.django_db
def test_update_webhook(
make_organization_and_user_with_token,
make_custom_webhook,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-detail", kwargs={"pk": webhook.public_primary_key})
data = {
"name": "RENAMED",
}
assert webhook.name != data["name"]
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
expected_result = _get_expected_result(webhook)
expected_result["name"] = data["name"]
assert response.status_code == status.HTTP_200_OK
webhook.refresh_from_db()
assert webhook.name == expected_result["name"]
assert response.data == expected_result
@pytest.mark.django_db
def test_delete_webhook(
make_organization_and_user_with_token,
make_custom_webhook,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-detail", kwargs={"pk": webhook.public_primary_key})
assert webhook.deleted_at is None
response = client.delete(url, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_204_NO_CONTENT
webhook.refresh_from_db()
assert webhook.deleted_at is not None
response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.data["detail"] == "Not found."
@pytest.mark.django_db
def test_get_webhook_responses(
make_organization_and_user_with_token,
make_custom_webhook,
make_webhook_response,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization)
webhook.refresh_from_db()
response_count = 20
for i in range(0, response_count):
make_webhook_response(
webhook=webhook,
trigger_type=webhook.trigger_type,
status_code=200,
content=json.dumps({"id": "third-party-id"}),
event_data=json.dumps({"test": "abc"}),
)
url = reverse("api-public:webhooks-responses", kwargs={"pk": webhook.public_primary_key})
response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook_response = response.data["results"][0]
assert webhook_response["status_code"] == 200
assert webhook_response["content"] == '{"id": "third-party-id"}'
assert webhook_response["event_data"] == '{"test": "abc"}'
assert response.data["count"] == 20
assert response.status_code == status.HTTP_200_OK
@pytest.mark.django_db
def test_webhook_validate_integration_filters(
make_organization_and_user_with_token,
make_custom_webhook,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_token()
alert_receive_channel = make_alert_receive_channel(organization)
webhook = make_custom_webhook(organization=organization)
url = reverse("api-public:webhooks-detail", kwargs={"pk": webhook.public_primary_key})
data = {"integration_filter": alert_receive_channel.public_primary_key}
client = APIClient()
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == 400
data["integration_filter"] = ["abc"]
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == 400
data["integration_filter"] = [alert_receive_channel.public_primary_key, alert_receive_channel.public_primary_key]
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == 400
data["integration_filter"] = [alert_receive_channel.public_primary_key]
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook.refresh_from_db()
assert response.status_code == 200
assert response.data["integration_filter"] == data["integration_filter"]
assert webhook.integration_filter == data["integration_filter"]
data["integration_filter"] = []
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook.refresh_from_db()
assert response.status_code == 200
assert response.data["integration_filter"] == data["integration_filter"]
assert webhook.integration_filter == data["integration_filter"]
data["integration_filter"] = None
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
webhook.refresh_from_db()
assert response.status_code == 200
assert response.data["integration_filter"] == data["integration_filter"]
assert webhook.integration_filter == data["integration_filter"]