oncall-engine/engine/apps/labels/tests/test_labels_cache.py

192 lines
8.1 KiB
Python
Raw Permalink Normal View History

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
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
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__
)
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
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
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
label_option = {
"key": {"id": label_association.key.id, "name": label_association.key.name},
"values": [{"id": label_association.value.id, "name": label_association.value.name}],
}
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
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__
)
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
assert mock_get_label_by_key_id.called
assert mock_update_cache.called
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
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(
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
"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__
)
Support prescribed labels (#3848) # 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>
2024-02-20 14:42:51 +08:00
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()