oncall-engine/engine/apps/labels/tests/test_labels_cache.py
Yulya Artyukhina dcb37417ef
Fix getting label by name (#5414)
# What this PR does
Handle JSONDecodeError on getting label key by name

## 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] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
2025-01-14 13:40:32 +00:00

191 lines
8.1 KiB
Python

from json import JSONDecodeError
from unittest.mock import call, patch
import pytest
from django.utils import timezone
from apps.labels.client import LabelsAPIClient, LabelsRepoAPIException
from apps.labels.models import LabelKeyCache, LabelValueCache
from apps.labels.tasks import update_instances_labels_cache, update_labels_cache
from apps.labels.utils import LABEL_OUTDATED_TIMEOUT_MINUTES
@pytest.mark.django_db
def test_update_labels_cache_for_key(make_organization, make_label_key_and_value, make_label_value):
organization = make_organization()
label_key, label_value1 = make_label_key_and_value(organization)
label_value2 = make_label_value(label_key)
new_key_name = "updatekeyname"
new_value1_name = "updatevalue1name"
old_value2_name = label_value2.name
last_synced = label_key.last_synced
label_data = {
"key": {"id": label_key.id, "name": new_key_name},
"values": [{"id": label_value1.id, "name": new_value1_name}, {"id": label_value2.id, "name": old_value2_name}],
}
assert label_key.name != new_key_name
assert label_value1.name != new_value1_name
update_labels_cache(label_data)
label_key.refresh_from_db()
label_value1.refresh_from_db()
label_value2.refresh_from_db()
for label_cache in (label_key, label_value1, label_value2):
assert label_cache.last_synced > last_synced
assert label_key.name == new_key_name
assert label_value1.name == new_value1_name
assert label_value2.name == old_value2_name
@pytest.mark.django_db
def test_update_labels_cache(make_organization, make_label_key_and_value, make_label_value):
organization = make_organization()
label_key1, label_value1_1 = make_label_key_and_value(organization)
label_key2, label_value2_1 = make_label_key_and_value(organization)
label_value2_2 = make_label_value(label_key2)
new_key1_name = "updatekey1name"
new_value1_1_name = "updatevalue11name"
old_key2_name = label_key2.name
old_value2_1_name = label_value2_1.name
new_value2_2_name = "updatevalue22name"
last_synced = label_key1.last_synced
labels_data = [
{
"key": {"id": label_key1.id, "name": new_key1_name},
"value": {"id": label_value1_1.id, "name": new_value1_1_name},
},
{
"key": {"id": label_key2.id, "name": old_key2_name},
"value": {"id": label_value2_1.id, "name": old_value2_1_name},
},
{
"key": {"id": label_key2.id, "name": old_key2_name},
"value": {"id": label_value2_2.id, "name": new_value2_2_name},
},
]
assert label_key1.name != new_key1_name
assert label_value1_1.name != new_value1_1_name
assert label_value2_2.name != new_value2_2_name
update_labels_cache(labels_data)
for label_cache in (label_key1, label_key2, label_value1_1, label_value2_1, label_value2_2):
label_cache.refresh_from_db()
assert label_cache.last_synced > last_synced
assert label_key1.name == new_key1_name
assert label_value1_1.name == new_value1_1_name
assert label_key2.name == old_key2_name
assert label_value2_1.name == old_value2_1_name
assert label_value2_2.name == new_value2_2_name
@pytest.mark.django_db
def test_update_instances_labels_cache_recently_synced(
make_organization, make_alert_receive_channel, make_static_label_config
):
organization = make_organization()
alert_receive_channel = make_alert_receive_channel(organization)
label_association = make_static_label_config(organization, alert_receive_channel)
assert not label_association.key.is_outdated
assert not label_association.value.is_outdated
with patch("apps.labels.client.LabelsAPIClient.get_label_by_key_id") as mock_get_label_by_key_id:
with patch("apps.labels.tasks.update_labels_cache.apply_async") as mock_update_cache:
update_instances_labels_cache(
organization.id, [alert_receive_channel.id], alert_receive_channel._meta.model.__name__
)
assert not mock_get_label_by_key_id.called
assert not mock_update_cache.called
@pytest.mark.django_db
def test_update_instances_labels_cache_outdated(
make_organization, make_alert_receive_channel, make_static_label_config
):
organization = make_organization()
alert_receive_channel = make_alert_receive_channel(organization)
label_association = make_static_label_config(organization, alert_receive_channel)
outdated_last_synced = timezone.now() - timezone.timedelta(minutes=LABEL_OUTDATED_TIMEOUT_MINUTES + 1)
LabelKeyCache.objects.filter(id=label_association.key_id).update(last_synced=outdated_last_synced)
LabelValueCache.objects.filter(id=label_association.value_id).update(last_synced=outdated_last_synced)
label_association.refresh_from_db()
assert label_association.key.is_outdated
assert label_association.value.is_outdated
label_option = {
"key": {"id": label_association.key.id, "name": label_association.key.name},
"values": [{"id": label_association.value.id, "name": label_association.value.name}],
}
with patch(
"apps.labels.client.LabelsAPIClient.get_label_by_key_id", return_value=(label_option, None)
) as mock_get_label_by_key_id:
with patch("apps.labels.tasks.update_label_option_cache.apply_async") as mock_update_cache:
update_instances_labels_cache(
organization.id, [alert_receive_channel.id], alert_receive_channel._meta.model.__name__
)
assert mock_get_label_by_key_id.called
assert mock_update_cache.called
assert mock_update_cache.call_args == call((label_option,))
@pytest.mark.django_db
def test_update_instances_labels_cache_error(make_organization, make_alert_receive_channel, make_static_label_config):
organization = make_organization()
alert_receive_channel = make_alert_receive_channel(organization)
label_association = make_static_label_config(organization, alert_receive_channel)
outdated_last_synced = timezone.now() - timezone.timedelta(minutes=LABEL_OUTDATED_TIMEOUT_MINUTES + 1)
LabelKeyCache.objects.filter(id=label_association.key_id).update(last_synced=outdated_last_synced)
LabelValueCache.objects.filter(id=label_association.value_id).update(last_synced=outdated_last_synced)
with patch(
"apps.labels.client.LabelsAPIClient.get_label_by_key_id", side_effect=LabelsRepoAPIException("test", "test")
) as mock_get_label_by_key_id:
with patch("apps.labels.tasks.update_labels_cache.apply_async") as mock_update_cache:
update_instances_labels_cache(
organization.id, [alert_receive_channel.id], alert_receive_channel._meta.model.__name__
)
mock_get_label_by_key_id.assert_called_once_with(label_association.key_id)
mock_update_cache.assert_not_called()
@pytest.mark.django_db
def test_get_or_create_label_key_cache_by_name(make_organization):
organization = make_organization()
label_key_data = {"id": "testid", "name": "testname", "prescribed": False}
# test empty response from label repo (json decode error)
with patch.object(LabelsAPIClient, "get_label_by_key_name", side_effect=JSONDecodeError("test", "test", 0)):
label = LabelKeyCache.get_or_create_by_name(organization, label_key_data["name"])
assert label is None
# test label does not exist in labels repo
with patch.object(LabelsAPIClient, "get_label_by_key_name", side_effect=LabelsRepoAPIException("test", "test")):
label = LabelKeyCache.get_or_create_by_name(organization, label_key_data["name"])
assert label is None
# test label does not exist in cache
with patch.object(LabelsAPIClient, "get_label_by_key_name", return_value=({"key": label_key_data}, None)):
label = LabelKeyCache.get_or_create_by_name(organization, label_key_data["name"])
assert label is not None
assert LabelKeyCache.objects.filter(id=label.id).exists()
# test label exists in cache
label = LabelKeyCache.get_or_create_by_name(organization, label_key_data["name"])
assert label is not None
assert LabelKeyCache.objects.filter(id=label.id).exists()