11from contextlib import AbstractContextManager
22
3+ import responses
4+
35from sentry import audit_log
46from sentry .api .serializers import serialize
57from sentry .constants import ObjectStatus
1315from sentry .testutils .outbox import outbox_runner
1416from sentry .testutils .silo import assume_test_silo_mode , region_silo_test
1517from sentry .workflow_engine .endpoints .validators .base .workflow import WorkflowValidator
16- from sentry .workflow_engine .models import Action , DataConditionGroup , Workflow
18+ from sentry .workflow_engine .models import (
19+ Action ,
20+ Condition ,
21+ DataConditionGroup ,
22+ DataConditionGroupAction ,
23+ Workflow ,
24+ WorkflowDataConditionGroup ,
25+ )
1726from sentry .workflow_engine .models .detector_workflow import DetectorWorkflow
27+ from sentry .workflow_engine .typings .notification_action import (
28+ ActionTarget ,
29+ ActionType ,
30+ SentryAppIdentifier ,
31+ )
1832from tests .sentry .workflow_engine .test_base import BaseWorkflowTest
1933
2034
@@ -54,7 +68,7 @@ def setUp(self) -> None:
5468 "enabled" : True ,
5569 "config" : {},
5670 "triggers" : {"logicType" : "any" , "conditions" : []},
57- "action_filters " : [],
71+ "actionFilters " : [],
5872 }
5973 validator = WorkflowValidator (
6074 data = self .valid_workflow ,
@@ -63,6 +77,15 @@ def setUp(self) -> None:
6377 validator .is_valid (raise_exception = True )
6478 self .workflow = validator .create (validator .validated_data )
6579
80+ self .sentry_app , self .sentry_app_installation = self .create_sentry_app_with_schema ()
81+ self .sentry_app_settings = [
82+ {"name" : "alert_prefix" , "value" : "[Not Good]" },
83+ {"name" : "channel" , "value" : "#ignored-errors" },
84+ {"name" : "best_emoji" , "value" : ":fire:" },
85+ {"name" : "teamId" , "value" : "1" },
86+ {"name" : "assigneeId" , "value" : "3" },
87+ ]
88+
6689 def test_simple (self ) -> None :
6790 self .valid_workflow ["name" ] = "Updated Workflow"
6891 response = self .get_success_response (
@@ -73,6 +96,116 @@ def test_simple(self) -> None:
7396 assert response .status_code == 200
7497 assert updated_workflow .name == "Updated Workflow"
7598
99+ @responses .activate
100+ def test_update_add_sentry_app_action (self ) -> None :
101+ """
102+ Test that adding a sentry app action to a workflow works as expected
103+ """
104+ responses .add (
105+ method = responses .POST ,
106+ url = "https://example.com/sentry/alert-rule" ,
107+ status = 200 ,
108+ )
109+ self .valid_workflow ["actionFilters" ] = [
110+ {
111+ "logicType" : "any" ,
112+ "conditions" : [
113+ {
114+ "type" : Condition .EQUAL .value ,
115+ "comparison" : 1 ,
116+ "conditionResult" : True ,
117+ }
118+ ],
119+ "actions" : [
120+ {
121+ "config" : {
122+ "sentryAppIdentifier" : SentryAppIdentifier .SENTRY_APP_ID ,
123+ "targetIdentifier" : str (self .sentry_app .id ),
124+ "targetType" : ActionType .SENTRY_APP ,
125+ },
126+ "data" : {"settings" : self .sentry_app_settings },
127+ "type" : Action .Type .SENTRY_APP ,
128+ },
129+ ],
130+ }
131+ ]
132+ response = self .get_success_response (
133+ self .organization .slug , self .workflow .id , raw_data = self .valid_workflow
134+ )
135+ updated_workflow = Workflow .objects .get (id = response .data .get ("id" ))
136+ action_filter = WorkflowDataConditionGroup .objects .get (workflow = updated_workflow )
137+ dcga = DataConditionGroupAction .objects .get (condition_group = action_filter .condition_group )
138+ action = dcga .action
139+
140+ assert response .status_code == 200
141+ assert action .type == Action .Type .SENTRY_APP
142+ assert action .config == {
143+ "sentry_app_identifier" : SentryAppIdentifier .SENTRY_APP_ID ,
144+ "target_identifier" : str (self .sentry_app .id ),
145+ "target_type" : ActionTarget .SENTRY_APP .value ,
146+ }
147+ assert action .data ["settings" ] == self .sentry_app_settings
148+
149+ @responses .activate
150+ def test_update_add_sentry_app_installation_uuid_action (self ) -> None :
151+ """
152+ Test that adding a sentry app action to a workflow works as expected when we pass the installation UUID instead of the sentry app id.
153+ We do not create new actions like this today, but we have data like this in the DB and need to make sure it still works until we can migrate away from it
154+ to use the sentry app id
155+ """
156+ responses .add (
157+ method = responses .POST ,
158+ url = "https://example.com/sentry/alert-rule" ,
159+ status = 200 ,
160+ )
161+ # update the settings
162+ updated_sentry_app_settings = [
163+ {"name" : "alert_prefix" , "value" : "[Very Good]" },
164+ {"name" : "channel" , "value" : "#pay-attention-to-errors" },
165+ {"name" : "best_emoji" , "value" : ":ice:" },
166+ {"name" : "teamId" , "value" : "1" },
167+ {"name" : "assigneeId" , "value" : "3" },
168+ ]
169+ self .valid_workflow ["actionFilters" ] = [
170+ {
171+ "logicType" : "any" ,
172+ "conditions" : [
173+ {
174+ "type" : Condition .EQUAL .value ,
175+ "comparison" : 1 ,
176+ "conditionResult" : True ,
177+ }
178+ ],
179+ "actions" : [
180+ {
181+ "config" : {
182+ "sentryAppIdentifier" : SentryAppIdentifier .SENTRY_APP_INSTALLATION_UUID ,
183+ "targetIdentifier" : self .sentry_app_installation .uuid ,
184+ "targetType" : ActionType .SENTRY_APP ,
185+ },
186+ "data" : {"settings" : updated_sentry_app_settings },
187+ "type" : Action .Type .SENTRY_APP ,
188+ },
189+ ],
190+ }
191+ ]
192+ response = self .get_success_response (
193+ self .organization .slug , self .workflow .id , raw_data = self .valid_workflow
194+ )
195+ updated_workflow = Workflow .objects .get (id = response .data .get ("id" ))
196+ action_filter = WorkflowDataConditionGroup .objects .get (workflow = updated_workflow )
197+ dcga = DataConditionGroupAction .objects .get (condition_group = action_filter .condition_group )
198+ action = dcga .action
199+
200+ assert response .status_code == 200
201+ assert action .type == Action .Type .SENTRY_APP
202+ assert action .config == {
203+ "sentry_app_identifier" : SentryAppIdentifier .SENTRY_APP_ID ,
204+ "target_identifier" : str (self .sentry_app .id ),
205+ "target_type" : ActionTarget .SENTRY_APP .value ,
206+ }
207+ assert action .data ["settings" ] == updated_sentry_app_settings
208+
76209 def test_update_triggers_with_empty_conditions (self ) -> None :
77210 """Test that passing an empty list to triggers.conditions clears all conditions"""
78211 # Create a workflow with a trigger condition
0 commit comments