firefighter-incident 0.0.35__py3-none-any.whl → 0.0.37__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from unittest.mock import Mock, patch
5
+ from unittest.mock import ANY, Mock, patch
6
6
 
7
7
  import pytest
8
8
  from django.test import override_settings
@@ -10,6 +10,7 @@ from django.test import override_settings
10
10
  from firefighter.incidents.enums import IncidentStatus
11
11
  from firefighter.incidents.models.incident_update import IncidentUpdate
12
12
  from firefighter.raid.signals.incident_updated import (
13
+ IMPACT_TO_JIRA_STATUS_MAP,
13
14
  incident_updated_close_ticket_when_mitigated_or_postmortem,
14
15
  )
15
16
 
@@ -18,11 +19,16 @@ from firefighter.raid.signals.incident_updated import (
18
19
  class TestIncidentUpdatedCloseJiraTicket:
19
20
  """Test that Jira tickets are closed when incidents reach terminal statuses."""
20
21
 
21
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
22
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
22
23
  def test_close_jira_ticket_when_status_changes_to_mitigated(
23
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory, priority_factory
24
+ self,
25
+ mock_transition: Mock,
26
+ incident_factory,
27
+ user_factory,
28
+ jira_ticket_factory,
29
+ priority_factory,
24
30
  ) -> None:
25
- """Test that Jira ticket is closed when incident status changes to MITIGATED for P3+."""
31
+ """Impact Jira: MITIGATED transitions to Reporter validation for P3+."""
26
32
  user = user_factory()
27
33
  # Create P3 priority (no postmortem needed)
28
34
  p3_priority = priority_factory(value=3, name="P3", needs_postmortem=False)
@@ -44,13 +50,19 @@ class TestIncidentUpdatedCloseJiraTicket:
44
50
  updated_fields=["_status"],
45
51
  )
46
52
 
47
- # Verify close_issue was called for P3+ incidents
48
- mock_close_issue.assert_called_once_with(issue_id=jira_ticket.id)
53
+ target = IMPACT_TO_JIRA_STATUS_MAP[IncidentStatus.MITIGATED]
54
+ mock_transition.assert_called_once_with(jira_ticket.id, target, ANY)
49
55
 
50
56
  @override_settings(ENABLE_JIRA_POSTMORTEM=True)
51
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
57
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
52
58
  def test_do_not_close_jira_ticket_when_p1_mitigated(
53
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory, priority_factory, environment_factory
59
+ self,
60
+ mock_transition: Mock,
61
+ incident_factory,
62
+ user_factory,
63
+ jira_ticket_factory,
64
+ priority_factory,
65
+ environment_factory,
54
66
  ) -> None:
55
67
  """Test that Jira ticket is NOT closed when P1 incident status changes to MITIGATED.
56
68
 
@@ -61,7 +73,9 @@ class TestIncidentUpdatedCloseJiraTicket:
61
73
  # Create P1 priority (needs postmortem)
62
74
  p1_priority = priority_factory(value=1, name="P1", needs_postmortem=True)
63
75
  prd_env = environment_factory(value="PRD", name="Production")
64
- incident = incident_factory(created_by=user, priority=p1_priority, environment=prd_env)
76
+ incident = incident_factory(
77
+ created_by=user, priority=p1_priority, environment=prd_env
78
+ )
65
79
  jira_ticket = jira_ticket_factory(incident=incident)
66
80
  incident.jira_ticket = jira_ticket
67
81
 
@@ -79,12 +93,12 @@ class TestIncidentUpdatedCloseJiraTicket:
79
93
  updated_fields=["_status"],
80
94
  )
81
95
 
82
- # Verify close_issue was NOT called - P1 needs to go through postmortem first
83
- mock_close_issue.assert_not_called()
96
+ target = IMPACT_TO_JIRA_STATUS_MAP[IncidentStatus.MITIGATED]
97
+ mock_transition.assert_called_once_with(jira_ticket.id, target, ANY)
84
98
 
85
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
99
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
86
100
  def test_do_not_close_jira_ticket_when_status_changes_to_postmortem(
87
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory
101
+ self, mock_transition: Mock, incident_factory, user_factory, jira_ticket_factory
88
102
  ) -> None:
89
103
  """Test that Jira ticket is NOT closed when incident status changes to POST_MORTEM.
90
104
 
@@ -110,12 +124,12 @@ class TestIncidentUpdatedCloseJiraTicket:
110
124
  updated_fields=["_status"],
111
125
  )
112
126
 
113
- # Verify close_issue was NOT called - ticket stays open during PM
114
- mock_close_issue.assert_not_called()
127
+ target = IMPACT_TO_JIRA_STATUS_MAP[IncidentStatus.POST_MORTEM]
128
+ mock_transition.assert_called_once_with(jira_ticket.id, target, ANY)
115
129
 
116
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
130
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
117
131
  def test_close_jira_ticket_when_status_changes_to_closed(
118
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory
132
+ self, mock_transition: Mock, incident_factory, user_factory, jira_ticket_factory
119
133
  ) -> None:
120
134
  """Test that Jira ticket is closed when incident status changes to CLOSED (direct close)."""
121
135
  user = user_factory()
@@ -137,12 +151,11 @@ class TestIncidentUpdatedCloseJiraTicket:
137
151
  updated_fields=["_status"],
138
152
  )
139
153
 
140
- # Verify close_issue was called
141
- mock_close_issue.assert_called_once_with(issue_id=jira_ticket.id)
154
+ mock_transition.assert_called_once_with(jira_ticket.id, "Closed", ANY)
142
155
 
143
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
156
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
144
157
  def test_do_not_close_jira_ticket_when_status_not_terminal(
145
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory
158
+ self, mock_transition: Mock, incident_factory, user_factory, jira_ticket_factory
146
159
  ) -> None:
147
160
  """Test that Jira ticket is NOT closed for non-terminal statuses."""
148
161
  user = user_factory()
@@ -164,12 +177,12 @@ class TestIncidentUpdatedCloseJiraTicket:
164
177
  updated_fields=["_status"],
165
178
  )
166
179
 
167
- # Verify close_issue was NOT called
168
- mock_close_issue.assert_not_called()
180
+ target = IMPACT_TO_JIRA_STATUS_MAP[IncidentStatus.INVESTIGATING]
181
+ mock_transition.assert_called_once_with(jira_ticket.id, target, ANY)
169
182
 
170
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
183
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
171
184
  def test_do_not_close_jira_ticket_when_status_not_updated(
172
- self, mock_close_issue: Mock, incident_factory, user_factory, jira_ticket_factory
185
+ self, mock_transition: Mock, incident_factory, user_factory, jira_ticket_factory
173
186
  ) -> None:
174
187
  """Test that Jira ticket is NOT closed when _status is not in updated_fields."""
175
188
  user = user_factory()
@@ -191,15 +204,14 @@ class TestIncidentUpdatedCloseJiraTicket:
191
204
  updated_fields=["priority_id"], # Not _status
192
205
  )
193
206
 
194
- # Verify close_issue was NOT called
195
- mock_close_issue.assert_not_called()
207
+ mock_transition.assert_not_called()
196
208
 
197
- @patch("firefighter.raid.signals.incident_updated.client.close_issue")
209
+ @patch("firefighter.raid.signals.incident_updated.client.transition_issue_auto")
198
210
  @patch("firefighter.raid.signals.incident_updated.logger")
199
211
  def test_do_not_crash_when_jira_ticket_missing(
200
212
  self,
201
213
  mock_logger: Mock,
202
- mock_close_issue: Mock,
214
+ mock_transition: Mock,
203
215
  incident_factory,
204
216
  user_factory,
205
217
  ) -> None:
@@ -222,8 +234,8 @@ class TestIncidentUpdatedCloseJiraTicket:
222
234
  updated_fields=["_status"],
223
235
  )
224
236
 
225
- # Verify close_issue was NOT called
226
- mock_close_issue.assert_not_called()
237
+ # Verify transition was NOT called
238
+ mock_transition.assert_not_called()
227
239
 
228
240
  # Verify a warning was logged
229
241
  mock_logger.warning.assert_called_once()
@@ -10,6 +10,8 @@ from pytest_mock import MockerFixture
10
10
  from firefighter.incidents.enums import IncidentStatus
11
11
  from firefighter.incidents.factories import IncidentFactory, UserFactory
12
12
  from firefighter.incidents.models import Incident, MilestoneType
13
+ from firefighter.incidents.models.environment import Environment
14
+ from firefighter.incidents.models.priority import Priority
13
15
  from firefighter.slack.views import UpdateStatusModal
14
16
 
15
17
  logger = logging.getLogger(__name__)
@@ -223,9 +225,35 @@ class TestUpdateStatusModal:
223
225
 
224
226
  # Create a P1/P2 incident in POST_MORTEM status
225
227
  # This incident will have missing milestones (detected, started)
228
+ priority = (
229
+ Priority.objects.filter(value=1).first()
230
+ or Priority.objects.create(
231
+ value=1,
232
+ name="P1",
233
+ order=1,
234
+ emoji="🔴",
235
+ needs_postmortem=True,
236
+ enabled_create=True,
237
+ enabled_update=True,
238
+ default=False,
239
+ )
240
+ )
241
+ environment = (
242
+ Environment.objects.filter(value="PRD").first()
243
+ or Environment.objects.create(
244
+ value="PRD",
245
+ name="Production",
246
+ description="Production",
247
+ order=1,
248
+ default=False,
249
+ )
250
+ )
251
+
226
252
  incident = IncidentFactory.create(
227
253
  _status=IncidentStatus.POST_MORTEM,
228
254
  created_by=user,
255
+ priority=priority,
256
+ environment=environment,
229
257
  )
230
258
 
231
259
  # Verify that can_be_closed returns False due to missing milestones