From cc92c53f843c95dec86f43eae51c7a5fee8f3e10 Mon Sep 17 00:00:00 2001 From: Yulya Artyukhina Date: Mon, 4 Sep 2023 13:10:28 +0200 Subject: [PATCH] Fix build escalation snapshot (#2954) # What this PR does Fix escalation snapshot building if last notified user in escalation step "Notify users one by one (round-robin)" was deleted ## Which issue(s) this PR fixes https://github.com/grafana/oncall-private/issues/2148 ## 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) --- CHANGELOG.md | 1 + .../serializers/escalation_policy_snapshot.py | 1 + .../alerts/tests/test_escalation_snapshot.py | 52 +++++++++++++++++++ .../apps/api/tests/test_escalation_policy.py | 3 ++ 4 files changed, 57 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9c322c8e3..5a648c22c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix for Cloud plugin install not refreshing page after completion ([2974](https://github.com/grafana/oncall/issues/2874)) +- Fix escalation snapshot building if user was deleted @Ferril ([#2954](https://github.com/grafana/oncall/pull/2954)) ## v1.3.30 (2023-08-31) diff --git a/engine/apps/alerts/escalation_snapshot/serializers/escalation_policy_snapshot.py b/engine/apps/alerts/escalation_snapshot/serializers/escalation_policy_snapshot.py index d097833e40..6d648af2bf 100644 --- a/engine/apps/alerts/escalation_snapshot/serializers/escalation_policy_snapshot.py +++ b/engine/apps/alerts/escalation_snapshot/serializers/escalation_policy_snapshot.py @@ -64,6 +64,7 @@ class EscalationPolicySnapshotSerializer(serializers.ModelSerializer): num_alerts_in_window = serializers.IntegerField(allow_null=True, default=None) num_minutes_in_window = serializers.IntegerField(allow_null=True, default=None) pause_escalation = serializers.BooleanField(default=False) + last_notified_user = PrimaryKeyRelatedFieldWithNoneValue(allow_null=True, queryset=User.objects) class Meta: model = EscalationPolicy diff --git a/engine/apps/alerts/tests/test_escalation_snapshot.py b/engine/apps/alerts/tests/test_escalation_snapshot.py index 66003eebca..da0b630483 100644 --- a/engine/apps/alerts/tests/test_escalation_snapshot.py +++ b/engine/apps/alerts/tests/test_escalation_snapshot.py @@ -266,3 +266,55 @@ def test_escalation_snapshot_non_sequential_orders( policy_ids = [p.id for p in escalation_snapshot.executed_escalation_policy_snapshots] assert policy_ids == [step_1.id, step_2.id] + + +@pytest.mark.django_db +def test_serialize_escalation_snapshot_with_deleted_user( + make_organization_and_user, + make_user_for_organization, + make_alert_receive_channel, + make_channel_filter, + make_escalation_chain, + make_escalation_policy, + make_alert_group, +): + organization, user = make_organization_and_user() + alert_receive_channel = make_alert_receive_channel(organization) + escalation_chain = make_escalation_chain(organization) + channel_filter = make_channel_filter( + alert_receive_channel, + escalation_chain=escalation_chain, + notification_backends={"BACKEND": {"channel_id": "abc123"}}, + ) + + notify_users_queue = make_escalation_policy( + escalation_chain=channel_filter.escalation_chain, + escalation_policy_step=EscalationPolicy.STEP_NOTIFY_USERS_QUEUE, + last_notified_user=user, + ) + notify_users_queue.notify_to_users_queue.set([user]) + + alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter) + alert_group.raw_escalation_snapshot = alert_group.build_raw_escalation_snapshot() + alert_group.save() + escalation_snapshot = alert_group.escalation_snapshot + + assert notify_users_queue.last_notified_user == user + assert escalation_snapshot.escalation_policies_snapshots[0].last_notified_user == user + assert len(escalation_snapshot.escalation_policies_snapshots[0].notify_to_users_queue) == 1 + + # delete user + user.is_active = None + user.save() + + alert_group.raw_escalation_snapshot = alert_group.build_raw_escalation_snapshot() + # clear cached_property + del alert_group.escalation_snapshot + alert_group.save() + + escalation_snapshot = alert_group.escalation_snapshot + + assert notify_users_queue.last_notified_user == user + assert escalation_snapshot is not None + assert escalation_snapshot.escalation_policies_snapshots[0].last_notified_user is None + assert len(escalation_snapshot.escalation_policies_snapshots[0].notify_to_users_queue) == 0 diff --git a/engine/apps/api/tests/test_escalation_policy.py b/engine/apps/api/tests/test_escalation_policy.py index bbb753294b..f14d4daaca 100644 --- a/engine/apps/api/tests/test_escalation_policy.py +++ b/engine/apps/api/tests/test_escalation_policy.py @@ -846,6 +846,9 @@ def test_escalation_policy_filter_by_user( assert response.status_code == status.HTTP_200_OK + result = response.json() + assert set(result[1]["notify_to_users_queue"]) == {user.public_primary_key, second_user.public_primary_key} + expected_payload[1]["notify_to_users_queue"] = result[1]["notify_to_users_queue"] assert response.json() == expected_payload