# What this PR does **Cleanup label typing:** 1. LabelParam -> two separate types LabekKey and LabelValue 2. LabelData -> renamed to LabelPair. 3. LabelKeyData -> renamed to LabelOption Data is not giving any info about what this type represents. 4. Remove LabelsData and LabelsKeysData types. They are just list of types listed above and with new naming it feels obsolete. 5. ValueData removed. LabelPair is used instead. 6. Rework AlertGroupCustomLabel to use LabelKey type for key to make type system more consistent. Name model type AlertGroupCustomLabel**DB** and api type AlertGroupCustomLabel**API** to clearly distinguish them. **Split update_labels_cache into two tasks** update_label_option_cache and update_label_pairs_cache. Original task was expecting array of LabelsData (now it's LabelPair) OR one LabelKeyData ( now it's LabelOption). I believe having one function with two sp different argument types makes it more complicated for understanding. **Make OnCall backend support prescribed labels**. OnCall will sync and store "prescribed" field for key and values, so Label dropdown able to disable editing for certain labels. ## Which issue(s) this PR fixes ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [ ] 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) --------- Co-authored-by: Maxim Mordasov <maxim.mordasov@grafana.com> Co-authored-by: Yulya Artyukhina <Ferril.darkdiver@gmail.com>
162 lines
6.8 KiB
Python
162 lines
6.8 KiB
Python
from unittest.mock import call, patch
|
|
|
|
import pytest
|
|
from django.utils import timezone
|
|
|
|
from apps.labels.client import 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_integration_label_association
|
|
):
|
|
organization = make_organization()
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
label_association = make_integration_label_association(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_integration_label_association
|
|
):
|
|
organization = make_organization()
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
label_association = make_integration_label_association(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_integration_label_association
|
|
):
|
|
organization = make_organization()
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
label_association = make_integration_label_association(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()
|