Follow up test PR to https://github.com/grafana/oncall/pull/5199 and https://github.com/grafana/oncall/pull/5224
225 lines
8.4 KiB
Python
225 lines
8.4 KiB
Python
import json
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.utils import timezone
|
|
|
|
from apps.base.models import UserNotificationPolicy
|
|
from apps.schedules.models import CustomOnCallShift, OnCallScheduleWeb
|
|
from apps.slack.chatops_proxy_routing import make_private_metadata, make_value
|
|
from apps.slack.scenarios.manage_responders import (
|
|
ALERT_GROUP_DATA_KEY,
|
|
DIRECT_PAGING_USER_SELECT_ID,
|
|
USER_DATA_KEY,
|
|
ManageRespondersRemoveUser,
|
|
ManageRespondersUserChange,
|
|
StartManageResponders,
|
|
)
|
|
from apps.slack.scenarios.paging import _get_users_select
|
|
|
|
ORGANIZATION_ID = 12
|
|
ALERT_GROUP_ID = 42
|
|
TRIGGER_ID = "111"
|
|
CHANNEL_ID = "123"
|
|
MESSAGE_TS = "67"
|
|
|
|
|
|
def make_slack_payload(organization, user=None, actions=None):
|
|
payload = {
|
|
"trigger_id": TRIGGER_ID,
|
|
"view": {
|
|
"id": "view-id",
|
|
"private_metadata": make_private_metadata(
|
|
{"input_id_prefix": "", ALERT_GROUP_DATA_KEY: ALERT_GROUP_ID}, organization
|
|
),
|
|
"state": {
|
|
"values": {
|
|
DIRECT_PAGING_USER_SELECT_ID: {
|
|
ManageRespondersUserChange.routing_uid(): {
|
|
"selected_option": {"value": make_value({"id": user.pk}, organization)} if user else None
|
|
}
|
|
},
|
|
}
|
|
},
|
|
},
|
|
}
|
|
if actions is not None:
|
|
payload["actions"] = actions
|
|
return payload
|
|
|
|
|
|
@pytest.fixture
|
|
def manage_responders_setup(
|
|
make_organization_and_user_with_slack_identities,
|
|
make_alert_receive_channel,
|
|
make_alert_group,
|
|
make_alert,
|
|
make_slack_channel,
|
|
make_slack_message,
|
|
):
|
|
organization, user, slack_team_identity, slack_user_identity = make_organization_and_user_with_slack_identities()
|
|
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
alert_group = make_alert_group(alert_receive_channel, pk=ALERT_GROUP_ID)
|
|
make_alert(alert_group, raw_request_data={})
|
|
|
|
slack_channel = make_slack_channel(slack_team_identity, slack_id=CHANNEL_ID)
|
|
make_slack_message(alert_group=alert_group, channel_id=slack_channel.slack_id, slack_id=MESSAGE_TS)
|
|
|
|
return organization, user, slack_team_identity, slack_user_identity
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_initial_state(manage_responders_setup):
|
|
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
|
payload = {
|
|
"trigger_id": TRIGGER_ID,
|
|
"actions": [
|
|
{
|
|
"type": "button",
|
|
"value": json.dumps({"organization_id": organization.pk, "alert_group_pk": ALERT_GROUP_ID}),
|
|
}
|
|
],
|
|
}
|
|
step = StartManageResponders(slack_team_identity, organization, user)
|
|
with patch.object(step._slack_client, "views_open") as mock_slack_api_call:
|
|
step.process_scenario(slack_user_identity, slack_team_identity, payload)
|
|
|
|
metadata = json.loads(mock_slack_api_call.call_args.kwargs["view"]["private_metadata"])
|
|
assert metadata[ALERT_GROUP_DATA_KEY] == ALERT_GROUP_ID
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_add_user_no_warning(manage_responders_setup, make_schedule, make_on_call_shift, make_user_notification_policy):
|
|
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
|
|
|
# set up schedule: user is on call
|
|
schedule = make_schedule(
|
|
organization,
|
|
schedule_class=OnCallScheduleWeb,
|
|
team=None,
|
|
)
|
|
now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
start_date = now - timezone.timedelta(days=7)
|
|
data = {
|
|
"start": start_date,
|
|
"rotation_start": start_date,
|
|
"duration": timezone.timedelta(hours=23, minutes=59, seconds=59),
|
|
"priority_level": 1,
|
|
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
|
|
"schedule": schedule,
|
|
}
|
|
on_call_shift = make_on_call_shift(
|
|
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
|
|
)
|
|
on_call_shift.add_rolling_users([[user]])
|
|
schedule.refresh_ical_file()
|
|
schedule.refresh_ical_final_schedule()
|
|
# setup notification policy
|
|
make_user_notification_policy(
|
|
user=user,
|
|
step=UserNotificationPolicy.Step.NOTIFY,
|
|
notify_by=UserNotificationPolicy.NotificationChannel.SMS,
|
|
)
|
|
|
|
payload = make_slack_payload(organization, user=user)
|
|
|
|
step = ManageRespondersUserChange(slack_team_identity, organization, user)
|
|
with patch.object(step._slack_client, "views_update") as mock_slack_api_call:
|
|
step.process_scenario(slack_user_identity, slack_team_identity, payload)
|
|
|
|
# check there's a delete button for the user
|
|
assert mock_slack_api_call.call_args.kwargs["view"]["blocks"][0]["accessory"]["value"] == make_value(
|
|
{"id": str(user.pk)}, organization
|
|
)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_add_user_raise_warning(manage_responders_setup):
|
|
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
|
# user is not on call
|
|
payload = make_slack_payload(organization, user=user)
|
|
|
|
step = ManageRespondersUserChange(slack_team_identity, organization, user)
|
|
with patch.object(step._slack_client, "views_push") as mock_slack_api_call:
|
|
step.process_scenario(slack_user_identity, slack_team_identity, payload)
|
|
|
|
assert mock_slack_api_call.call_args.kwargs["view"]["callback_id"] == "ManageRespondersConfirmUserChange"
|
|
text_from_blocks = "".join(
|
|
b["text"]["text"] for b in mock_slack_api_call.call_args.kwargs["view"]["blocks"] if b["type"] == "section"
|
|
)
|
|
assert (
|
|
"This user is not currently on-call. We don't recommend to page users outside on-call hours."
|
|
in text_from_blocks
|
|
)
|
|
metadata = json.loads(mock_slack_api_call.call_args.kwargs["view"]["private_metadata"])
|
|
assert metadata[USER_DATA_KEY] == user.pk
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_remove_user(manage_responders_setup):
|
|
organization, user, slack_team_identity, slack_user_identity = manage_responders_setup
|
|
|
|
payload = make_slack_payload(organization, actions=[{"value": make_value({"id": user.pk}, organization)}])
|
|
step = ManageRespondersRemoveUser(slack_team_identity, organization, user)
|
|
with patch.object(step._slack_client, "views_update") as mock_slack_api_call:
|
|
step.process_scenario(slack_user_identity, slack_team_identity, payload)
|
|
|
|
# check there's no list of users in the view
|
|
assert mock_slack_api_call.call_args.kwargs["view"]["blocks"][0]["element"]["type"] != "button"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_get_users_select(make_organization, make_user, make_schedule, make_on_call_shift):
|
|
organization = make_organization()
|
|
|
|
# not on-call users
|
|
for _ in range(3):
|
|
make_user(organization=organization)
|
|
|
|
oncall_user = make_user(organization=organization)
|
|
|
|
# set up schedule: user is on call
|
|
schedule = make_schedule(
|
|
organization,
|
|
schedule_class=OnCallScheduleWeb,
|
|
team=None,
|
|
)
|
|
now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
start_date = now - timezone.timedelta(days=7)
|
|
data = {
|
|
"start": start_date,
|
|
"rotation_start": start_date,
|
|
"duration": timezone.timedelta(hours=23, minutes=59, seconds=59),
|
|
"priority_level": 1,
|
|
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
|
|
"schedule": schedule,
|
|
}
|
|
on_call_shift = make_on_call_shift(
|
|
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
|
|
)
|
|
on_call_shift.add_rolling_users([[oncall_user]])
|
|
schedule.refresh_ical_file()
|
|
schedule.refresh_ical_final_schedule()
|
|
|
|
select_input = _get_users_select(
|
|
organization=organization, input_id_prefix="test", action_id="test", max_options_per_group=2
|
|
)
|
|
|
|
select_element = select_input["element"]
|
|
select_option_groups = select_element["option_groups"]
|
|
|
|
assert len(select_option_groups) == 3
|
|
assert "options" not in select_element
|
|
|
|
oncall_options = select_option_groups[0]
|
|
not_oncall_options_group1 = select_option_groups[1]
|
|
not_oncall_options_group2 = select_option_groups[2]
|
|
|
|
assert len(oncall_options["options"]) == 1
|
|
assert len(not_oncall_options_group1["options"]) == 2
|
|
assert len(not_oncall_options_group2["options"]) == 1
|
|
|
|
assert oncall_options["label"]["text"] == "On-call now"
|
|
assert not_oncall_options_group1["label"]["text"] == "Not on-call (1-2)"
|
|
assert not_oncall_options_group2["label"]["text"] == "Not on-call (3-4)"
|