def post(self, request, organization, alert_rule, alert_rule_trigger): """ Create an action on a trigger """ if not features.has( "organizations:incidents", organization, actor=request.user): raise ResourceDoesNotExist serializer = AlertRuleTriggerActionSerializer( context={ "organization": organization, "alert_rule": alert_rule, "trigger": alert_rule_trigger, "access": request.access, }, data=request.data, ) if serializer.is_valid(): try: action = serializer.save() except InvalidTriggerActionError as e: return Response(e.message, status=status.HTTP_400_BAD_REQUEST) return Response(serialize(action, request.user), status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def run_fail_validation_test(self, params, errors): base_params = self.valid_params.copy() base_params.update(params) serializer = AlertRuleTriggerActionSerializer(context=self.context, data=base_params) assert not serializer.is_valid() assert serializer.errors == errors
def _run_changed_fields_test(self, trigger, params, expected): serializer = AlertRuleTriggerActionSerializer(context=self.context, instance=trigger, data=params, partial=True) assert serializer.is_valid(), serializer.errors assert serializer._remove_unchanged_fields( trigger, serializer.validated_data) == expected
def test_validation_no_params(self): serializer = AlertRuleTriggerActionSerializer(context=self.context, data={}) assert not serializer.is_valid() field_is_required = ["This field is required."] assert serializer.errors == { "type": field_is_required, "targetType": field_is_required, "targetIdentifier": field_is_required, }
def test_slack(self): self.run_fail_validation_test( { "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SLACK).slug, "target_type": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.USER], "target_identifier": "123", }, { "targetType": ["Invalid target type for slack. Valid types are [specific]"] }, ) self.run_fail_validation_test( { "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SLACK).slug, "targetType": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SPECIFIC], "targetIdentifier": "123", }, {"integration": ["Integration must be provided for slack"]}, ) integration = Integration.objects.create( external_id="1", provider="slack", metadata={ "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx" }, ) integration.add_organization(self.organization, self.user) base_params = self.valid_params.copy() base_params.update({ "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SLACK).slug, "targetType": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SPECIFIC], "targetIdentifier": "123", "integration": six.text_type(integration.id), }) serializer = AlertRuleTriggerActionSerializer(context=self.context, data=base_params) assert serializer.is_valid() with self.assertRaises(serializers.ValidationError): serializer.save()
def test_valid_slack_channel_id(self): """ Test that when a valid Slack channel ID is provided, we look up the channel name and validate it against the targetIdentifier. """ integration = Integration.objects.create( external_id="1", provider="slack", metadata={ "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx" }, ) integration.add_organization(self.organization, self.user) base_params = self.valid_params.copy() base_params.update({ "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SLACK).slug, "targetType": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SPECIFIC], "targetIdentifier": "merp", "integration": str(integration.id), }) context = self.context.copy() context.update({"input_channel_id": "CSVK0921"}) responses.add( method=responses.GET, url="https://slack.com/api/conversations.info", status=200, content_type="application/json", body=json.dumps({ "ok": "true", "channel": { "name": "merp", "id": "CSVK0921" } }), ) serializer = AlertRuleTriggerActionSerializer(context=context, data=base_params) assert serializer.is_valid() serializer.save() # # Make sure the action was created. alert_rule_trigger_actions = list( AlertRuleTriggerAction.objects.filter(integration=integration)) assert len(alert_rule_trigger_actions) == 1
def test_invalid_slack_channel_id(self): """ Test that an invalid Slack channel ID is detected and blocks the action from being saved. """ integration = Integration.objects.create( external_id="1", provider="slack", metadata={ "access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx" }, ) integration.add_organization(self.organization, self.user) base_params = self.valid_params.copy() base_params.update({ "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SLACK).slug, "targetType": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SPECIFIC], "targetIdentifier": "merp", "integration": str(integration.id), }) context = self.context.copy() context.update({"input_channel_id": "M40W931"}) responses.add( method=responses.GET, url="https://slack.com/api/conversations.info", status=200, content_type="application/json", body=json.dumps({ "ok": False, "error": "channel_not_found" }), ) serializer = AlertRuleTriggerActionSerializer(context=context, data=base_params) assert not serializer.is_valid() # # Make sure the action was not created. alert_rule_trigger_actions = list( AlertRuleTriggerAction.objects.filter(integration=integration)) assert len(alert_rule_trigger_actions) == 0
def put(self, request, organization, alert_rule, alert_rule_trigger, alert_rule_trigger_action): serializer = AlertRuleTriggerActionSerializer( context={ "organization": organization, "alert_rule": alert_rule, "alert_rule_trigger": alert_rule_trigger, "access": request.access, }, instance=alert_rule_trigger_action, data=request.data, partial=True, ) if serializer.is_valid(): trigger = serializer.save() return Response(serialize(trigger, request.user), status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def test_create_and_update_sentry_app_action_success(self): responses.add( method=responses.POST, url="https://example.com/sentry/alert-rule", status=200, json={}, ) serializer = AlertRuleTriggerActionSerializer( context=self.context, data={ "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SENTRY_APP).slug, "target_type": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SENTRY_APP], "target_identifier": "1", "sentry_app": self.sentry_app.id, "sentry_app_config": { "channel": "#general" }, "sentry_app_installation_uuid": self.sentry_app_installation.uuid, }, ) assert serializer.is_valid() # Create action serializer.save() # # Make sure the action was created. alert_rule_trigger_actions = list( AlertRuleTriggerAction.objects.filter(sentry_app=self.sentry_app)) assert len(alert_rule_trigger_actions) == 1 # Update action serializer = AlertRuleTriggerActionSerializer( context=self.context, data={ "type": AlertRuleTriggerAction.get_registered_type( AlertRuleTriggerAction.Type.SENTRY_APP).slug, "target_type": action_target_type_to_string[ AlertRuleTriggerAction.TargetType.SENTRY_APP], "target_identifier": "1", "sentry_app": self.sentry_app.id, "sentry_app_config": { "channel": "#announcements" }, "sentry_app_installation_uuid": self.sentry_app_installation.uuid, }, instance=alert_rule_trigger_actions[0], ) assert serializer.is_valid() # Update action serializer.save() alert_rule_trigger_action = AlertRuleTriggerAction.objects.get( sentry_app=self.sentry_app) # Make sure the changes got applied assert alert_rule_trigger_action.sentry_app_config == { "channel": "#announcements" }