From 2a55c3cb764e126147b135bfc8385a45ada6f3a4 Mon Sep 17 00:00:00 2001 From: Avery Lee Date: Fri, 22 Nov 2024 17:43:07 -0800 Subject: [PATCH 1/2] Fixes listing empty incidents in Slack. --- requirements-dev.in | 2 + requirements-dev.txt | 4 + .../dispatch_slack/incident/interactive.py | 2 + tests/conftest.py | 12 +++ tests/factories.py | 11 +-- ...est_dispatch_slack_incident_interactive.py | 80 +++++++++++++++++++ 6 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 tests/plugins/test_dispatch_slack_incident_interactive.py diff --git a/requirements-dev.in b/requirements-dev.in index 43f459d08a6a..de08d461f9ea 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -3,10 +3,12 @@ black click coverage devtools +easydict factory-boy faker ipython pre-commit pytest==7.4.4 +pytest-mock ruff vulture diff --git a/requirements-dev.txt b/requirements-dev.txt index ef6148f23c61..f492bdb78720 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,6 +26,8 @@ devtools==0.12.2 # via -r requirements-dev.in distlib==0.3.9 # via virtualenv +easydict==1.13 + # via -r requirements-dev.in executing==2.1.0 # via # devtools @@ -82,6 +84,8 @@ pygments==2.18.0 # ipython pytest==7.4.4 # via -r requirements-dev.in +pytest-mock==3.14.0 + # via -r requirements-dev.in python-dateutil==2.9.0.post0 # via faker pyyaml==6.0.2 diff --git a/src/dispatch/plugins/dispatch_slack/incident/interactive.py b/src/dispatch/plugins/dispatch_slack/incident/interactive.py index a27253e04600..74f86be2cc52 100644 --- a/src/dispatch/plugins/dispatch_slack/incident/interactive.py +++ b/src/dispatch/plugins/dispatch_slack/incident/interactive.py @@ -455,6 +455,8 @@ def handle_list_incidents_command( # Don't add a divider if we are at the last incident if idx != len(open_incidents): blocks.extend([Divider()]) + else: + blocks.append(Section(text="No incidents found.")) modal = Modal( title="Incident List", diff --git a/tests/conftest.py b/tests/conftest.py index 9f36dc7b37fa..14ecb212e282 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,7 @@ import pytest + +from easydict import EasyDict +from slack_sdk.web.client import WebClient from sqlalchemy_utils import drop_database, database_exists from starlette.config import environ from starlette.testclient import TestClient @@ -675,3 +678,12 @@ def cost_model_activity(session): @pytest.fixture def service_feedback(session): return ServiceFeedbackFactory() + + +@pytest.fixture() +def mock_slack_client(mocker): + mocks = EasyDict() + + mocks.views_open = mocker.patch.object(WebClient, "views_open") + + return mocks diff --git a/tests/factories.py b/tests/factories.py index eb225343be60..f288ad4920a9 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -518,6 +518,7 @@ class ParticipantFactory(BaseFactory): added_reason = Sequence(lambda n: f"added_reason{n}") after_hours_notification = Faker().pybool() user_conversation_id = FuzzyText() + individual = SubFactory(IndividualContactFactory) class Meta: """Factory Configuration.""" @@ -532,14 +533,6 @@ def incident(self, create, extracted, **kwargs): if extracted: self.incident_id = extracted.id - @post_generation - def individual_contact(self, create, extracted, **kwargs): - if not create: - return - - if extracted: - self.individual_contact_id = extracted.id - @post_generation def team(self, create, extracted, **kwargs): if not create: @@ -918,6 +911,7 @@ class IncidentFactory(BaseFactory): incident_priority = SubFactory(IncidentPriorityFactory) incident_severity = SubFactory(IncidentSeverityFactory) project = SubFactory(ProjectFactory) + commander = SubFactory(ParticipantFactory) conversation = SubFactory(ConversationFactory) class Meta: @@ -933,6 +927,7 @@ def participants(self, create, extracted, **kwargs): if extracted: for participant in extracted: self.participants.append(participant) + self.participants.append(self.commander) class TaskFactory(ResourceBaseFactory): diff --git a/tests/plugins/test_dispatch_slack_incident_interactive.py b/tests/plugins/test_dispatch_slack_incident_interactive.py new file mode 100644 index 000000000000..de1adcd98b6a --- /dev/null +++ b/tests/plugins/test_dispatch_slack_incident_interactive.py @@ -0,0 +1,80 @@ +def test_configure(): + """Test that we can configure the plugin.""" + from dispatch.plugins.dispatch_slack.incident.interactive import ( + configure, + ) + from easydict import EasyDict + + config = EasyDict( + { + "api_bot_token": "xoxb-12345", + "socket_mode_app_token": "xapp-12345", + "signing_secret": "test-123", + "app_user_slug": "test", + "ban_threads": True, + "timeline_event_reaction": "stopwatch", + "slack_command_tasks": "/dispatch-list-tasks", + "slack_command_list_my_tasks": "/dispatch-list-my-tasks", + "slack_command_list_participants": "/dispatch-list-participants", + "slack_command_assign_role": "/dispatch-assign-role", + "slack_command_update_incident": "/dispatch-update-incident", + "slack_command_update_participant": "/dispatch-update-participant", + "slack_command_engage_oncall": "/dispatch-engage-oncall", + "slack_command_list_resource": "/dispatch-list-resources", + "slack_command_report_incident": "/dispatch-report-incident", + "slack_command_report_tactical": "/dispatch-report-tactical", + "slack_command_report_executive": "/dispatch-report-executive", + "slack_command_update_notifications_group": "/dispatch-notifications-group", + "slack_command_add_timeline_event": "/dispatch-add-timeline-event", + "slack_command_list_incidents": "/dispatch-list-incidents", + "slack_command_run_workflow": "/dispatch-run-workflow", + "slack_command_list_workflow": "/dispatch-list-workflows", + "slack_command_list_tasks": "/dispatch-list-tasks", + "slack_command_create_task": "/dispatch-create-task", + } + ) + + configure(config) + + +def test_handle_tag_search_action(session, incident): + from dispatch.plugins.dispatch_slack.incident.interactive import ( + handle_tag_search_action, + ) + from slack_bolt import Ack + from easydict import EasyDict + + bolt_context = EasyDict({"subject": incident}) + payload = {"value": "payload"} + + handle_tag_search_action(ack=Ack(), payload=payload, context=bolt_context, db_session=session) + + +def test_handle_list_incidents_command(session, incident, mock_slack_client): + """Test that we can handle the list incidents command.""" + from dispatch.plugins.dispatch_slack.incident.interactive import ( + handle_list_incidents_command, + ) + from slack_bolt import Ack + from easydict import EasyDict + from dispatch.plugins.dispatch_slack.models import SubjectMetadata, IncidentSubjects + + subject = SubjectMetadata( + type=IncidentSubjects.incident, + id=incident.id, + organization_slug=incident.project.slug, + project_id=incident.project.id, + ) + + bolt_context = EasyDict({"subject": subject, "db_session": session}) + body = EasyDict({"trigger_id": "trigger_id"}) + payload = {"value": "payload"} + + handle_list_incidents_command( + ack=Ack(), + body=body, + payload=payload, + context=bolt_context, + db_session=session, + client=mock_slack_client, + ) From 0dfe750e045dbc6cef186d4e047f713b6b206fc6 Mon Sep 17 00:00:00 2001 From: Avery Lee Date: Fri, 22 Nov 2024 17:47:13 -0800 Subject: [PATCH 2/2] Simplify tests. --- tests/plugins/test_dispatch_slack_incident_interactive.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/plugins/test_dispatch_slack_incident_interactive.py b/tests/plugins/test_dispatch_slack_incident_interactive.py index de1adcd98b6a..c712be1a9677 100644 --- a/tests/plugins/test_dispatch_slack_incident_interactive.py +++ b/tests/plugins/test_dispatch_slack_incident_interactive.py @@ -42,9 +42,8 @@ def test_handle_tag_search_action(session, incident): handle_tag_search_action, ) from slack_bolt import Ack - from easydict import EasyDict - bolt_context = EasyDict({"subject": incident}) + bolt_context = {"subject": incident} payload = {"value": "payload"} handle_tag_search_action(ack=Ack(), payload=payload, context=bolt_context, db_session=session) @@ -56,7 +55,6 @@ def test_handle_list_incidents_command(session, incident, mock_slack_client): handle_list_incidents_command, ) from slack_bolt import Ack - from easydict import EasyDict from dispatch.plugins.dispatch_slack.models import SubjectMetadata, IncidentSubjects subject = SubjectMetadata( @@ -66,8 +64,8 @@ def test_handle_list_incidents_command(session, incident, mock_slack_client): project_id=incident.project.id, ) - bolt_context = EasyDict({"subject": subject, "db_session": session}) - body = EasyDict({"trigger_id": "trigger_id"}) + bolt_context = {"subject": subject, "db_session": session} + body = {"trigger_id": "trigger_id"} payload = {"value": "payload"} handle_list_incidents_command(