Skip to content

feat(workflow_engine): Refactor the Data Condition Validator #88050

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 3, 2025

Conversation

saponifi3d
Copy link
Contributor

@saponifi3d saponifi3d commented Mar 26, 2025

Description

  • Separate the DataCondition and DataConditionGroup validators
  • Add tests to the BaseDataConditionGroupValidator
  • Add tests for BaseDataConditionValidator
  • Create AbstractDataConditionValidator to easily allow definitions, this meant we could completely remove the numeric validator as we can just use the abstract validator.

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 26, 2025

comparison = serializers.JSONField(required=True)
condition_result = serializers.JSONField(required=True)
# condition_group_id = serializers.IntegerField(required=True)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, this is on purpose. need to think through the data condition group a little more in another PR then think about how this ties together. I think in general, it's correct that we would just want the ID at this point.

Copy link

codecov bot commented Mar 26, 2025

Codecov Report

Attention: Patch coverage is 92.12963% with 17 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...engine/endpoints/validators/base/data_condition.py 78.72% 10 Missing ⚠️
src/sentry/incidents/metric_alert_detector.py 85.71% 4 Missing ⚠️
...oints/validators/test_base_data_condition_group.py 85.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #88050       +/-   ##
===========================================
+ Coverage   51.71%   87.77%   +36.05%     
===========================================
  Files        9914    10016      +102     
  Lines      563395   568062     +4667     
  Branches    22208    22208               
===========================================
+ Hits       291358   498613   +207255     
+ Misses     271635    69047   -202588     
  Partials      402      402               

… SOLID design for metric alert comparison with new base
@saponifi3d saponifi3d marked this pull request as ready for review March 27, 2025 06:44
@saponifi3d saponifi3d requested review from a team as code owners March 27, 2025 06:44
@cathteng cathteng requested a review from a team March 27, 2025 16:24

class BaseDataConditionGroupValidator(CamelSnakeSerializer):
logic_type = serializers.CharField(required=True)
organization_id = serializers.IntegerField(required=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to validate that this is a real organization id? i think project/org is usually left out of the serializer because we validate the project/org based on the url path param, and we pass it as context instead

serializer = DrfRuleSerializer(
context={"project": project, "organization": project.organization}, data=request.data
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 yeah, i saw some of those too. can update to follow that pattern. (there are so many patterns for these in our codebase it's hard to tell what is "right" 😅)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a common pattern, although we could also build an OrganizationField or something if we need to validate in this class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll address in a separate PR for the Groups 👍 -- this is just moving the code out of the data_condition file and giving it a new home :)

@cathteng cathteng requested a review from a team March 27, 2025 16:50
conditions = serializers.ListField(required=True)

def validate_conditions(self, value):
MetricAlertComparisonConditionValidator(data=value, many=True).is_valid(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense do define this many=True behaviour on the base class, and define the validator as a property? Or do you think there will be more customizations to validate_conditions in the future that don't fit this model?

As an example of what I mean, in BaseDataConditionGroupValidator we could do

    def validate_conditions(self, value) -> list:
        self.validator(data=value, many=True).is_valid(raise_exception=True)

Then we wouldn't need to define this at all on this subclass. Not sure if the validator needs to explicitly implement something to support many?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree -- this was just to fix some mypy typing issues - hoping to address the DataConditionGroup stuff in a separate PR, but wanted to move it away from the DataCondition code and there was a little bit of extra fallout 😅


class BaseDataConditionGroupValidator(CamelSnakeSerializer):
logic_type = serializers.CharField(required=True)
organization_id = serializers.IntegerField(required=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a common pattern, although we could also build an OrganizationField or something if we need to validate in this class

…ition and updated implementation of the detector condition. refocused pr to data condition and removed some things around data condition groups

return value


class BaseActionValidator(CamelSnakeModelSerializer[T], Generic[T]):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just fyi, my plan is to come back in another PR to restructure this + the data condition group stuff, once we hammer down a format in this PR.

Comment on lines +37 to +39
class BaseDataConditionValidator(
AbstractDataConditionValidator[Any, Any],
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to make sure i understand, this validator is for any condition that is not one of the CONDITION_OPS, conditions that use something in CONDITION_OPS will implement AbstractDataConditionValidator like MetricAlertComparisonConditionValidator?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 yeah - yuuup. this BaseDataConditionValidator will respond to any custom handler. if we don't have a custom handler and it's just a condition op, you only need to setup the validator in the API layer using this.

PS, i am planning to change the BaseDataConditionValidator name to DataConditionValidator in a future pr to help with any confusion around it. Base reads like it should be extended to me, and in this case, it's the generic implementation. i figured the diff was big enough on this PR already though.

organization_id = serializers.IntegerField(required=True)
conditions = BaseDataConditionValidator(many=True)
try:
return validate_json_schema(value, handler.condition_result_schema)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to make a task to add these for each handler, should they be enforced in the pre-save signal too? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah - another area i'm trying to limit scope of the PR to. This was mostly to confirm it works.

@saponifi3d saponifi3d enabled auto-merge (squash) April 3, 2025 20:11
@saponifi3d saponifi3d merged commit f0e63ed into master Apr 3, 2025
48 checks passed
@saponifi3d saponifi3d deleted the jcallender/aci/data-condition-validators branch April 3, 2025 20:39
andrewshie-sentry pushed a commit that referenced this pull request Apr 8, 2025
## Description
- Separate the DataCondition and DataConditionGroup validators
- Add tests to the BaseDataConditionGroupValidator
- Add tests for BaseDataConditionValidator
- Create `AbstractDataConditionValidator` to easily allow definitions,
this meant we could completely remove the numeric validator as we can
just use the abstract validator.

---------

Co-authored-by: Cathy Teng <[email protected]>
@github-actions github-actions bot locked and limited conversation to collaborators Apr 19, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants