Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/sentry/preprod/size_analysis/grouptype.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def extract_dedupe_value(self, data_packet: SizeAnalysisDataPacket) -> int:


class PreprodSizeAnalysisDetectorValidator(BaseDetectorTypeValidator):
pass
data_source_required = False


@dataclass(frozen=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ class BaseDetectorTypeValidator(CamelSnakeSerializer[Any]):
This prevents invalid configurations for detector types that don't support multiple data sources.
"""

data_source_required = True
"""
Set to False in subclasses if data sources are not required for this detector type.
By default, data sources are required when creating a new detector.
"""

name = serializers.CharField(
required=True,
max_length=200,
Expand Down Expand Up @@ -137,6 +143,17 @@ def validate_condition_group(self, value: dict[str, Any]) -> dict[str, Any]:

return value

def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
"""
Validate detector data, enforcing data source requirements if configured.
"""
# Check if data sources are missing when creating a new detector
if self.data_source_required and not self.instance and not attrs.get("data_sources"):
raise serializers.ValidationError(
{"data_sources": ["This field is required when creating a detector."]}
)
return attrs

def get_quota(self) -> DetectorQuota:
return DetectorQuota(has_exceeded=False, limit=-1, count=-1)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@


class ErrorDetectorValidator(BaseDetectorTypeValidator):
data_source_required = False

fingerprinting_rules = serializers.CharField(required=False, allow_blank=True, allow_null=True)
resolve_age = EmptyIntegerField(
required=False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,19 @@ def test_missing_name(self) -> None:
)
assert response.data == {"name": ["This field is required."]}

def test_missing_data_sources(self) -> None:
data = {
"name": "Test Cron Monitor",
"type": MonitorIncidentType.slug,
"projectId": self.project.id,
}
response = self.get_error_response(
self.organization.slug,
**data,
status_code=400,
)
assert "dataSources" in response.data

def test_empty_query_string(self) -> None:
data = {**self.valid_data}
data["dataSources"][0]["query"] = ""
Expand Down
Loading