Skip to content

Commit 3504132

Browse files
Christinarlongevanh
authored andcommitted
chore(sentry apps): Improve tests and errors for select requester (#81038)
1 parent 8165c19 commit 3504132

File tree

2 files changed

+81
-7
lines changed

2 files changed

+81
-7
lines changed

src/sentry/sentry_apps/external_requests/select_requester.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
2+
from collections.abc import Sequence
23
from dataclasses import dataclass, field
3-
from typing import Any
4+
from typing import Annotated, Any, TypedDict
45
from urllib.parse import urlencode, urlparse, urlunparse
56
from uuid import uuid4
67

@@ -17,6 +18,12 @@
1718
logger = logging.getLogger("sentry.sentry_apps.external_requests")
1819

1920

21+
class SelectRequesterResult(TypedDict, total=False):
22+
# Each contained Sequence of strings is of length 2 i.e ["label", "value"]
23+
choices: Sequence[Annotated[Sequence[str], 2]]
24+
defaultValue: str
25+
26+
2027
@dataclass
2128
class SelectRequester:
2229
"""
@@ -34,7 +41,7 @@ class SelectRequester:
3441
query: str | None = field(default=None)
3542
dependent_data: str | None = field(default=None)
3643

37-
def run(self) -> dict[str, Any]:
44+
def run(self) -> SelectRequesterResult:
3845
response: list[dict[str, str]] = []
3946
try:
4047
url = self._build_url()
@@ -71,7 +78,9 @@ def run(self) -> dict[str, Any]:
7178
message = "select-requester.request-failed"
7279

7380
logger.info(message, extra=extra)
74-
raise APIError from e
81+
raise APIError(
82+
f"Something went wrong while getting SelectFields from {self.sentry_app.slug}"
83+
) from e
7584

7685
if not self._validate_response(response):
7786
logger.info(
@@ -85,7 +94,7 @@ def run(self) -> dict[str, Any]:
8594
},
8695
)
8796
raise ValidationError(
88-
f"Invalid response format for SelectField in {self.sentry_app} from uri: {self.uri}"
97+
f"Invalid response format for SelectField in {self.sentry_app.slug} from uri: {self.uri}"
8998
)
9099
return self._format_response(response)
91100

@@ -107,14 +116,16 @@ def _build_url(self) -> str:
107116
urlparts[4] = urlencode(query)
108117
return str(urlunparse(urlparts))
109118

110-
def _validate_response(self, resp: list[dict[str, Any]]) -> bool:
119+
# response format must be:
120+
# https://docs.sentry.io/organization/integrations/integration-platform/ui-components/formfield/#uri-response-format
121+
def _validate_response(self, resp: Sequence[dict[str, Any]]) -> bool:
111122
return validate(instance=resp, schema_type="select")
112123

113-
def _format_response(self, resp: list[dict[str, Any]]) -> dict[str, Any]:
124+
def _format_response(self, resp: Sequence[dict[str, Any]]) -> SelectRequesterResult:
114125
# the UI expects the following form:
115126
# choices: [[label, value]]
116127
# default: [label, value]
117-
response: dict[str, Any] = {}
128+
response: SelectRequesterResult = {}
118129
choices: list[list[str]] = []
119130

120131
for option in resp:

tests/sentry/sentry_apps/external_requests/test_select_requester.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,66 @@ def test_500_response(self):
120120
assert len(requests) == 1
121121
assert requests[0]["response_code"] == 500
122122
assert requests[0]["event_type"] == "select_options.requested"
123+
124+
@responses.activate
125+
def test_api_error_message(self):
126+
responses.add(
127+
method=responses.GET,
128+
url=f"https://example.com/get-issues?installationId={self.install.uuid}&projectSlug={self.project.slug}",
129+
body="Something failed",
130+
status=500,
131+
)
132+
133+
with pytest.raises(APIError) as exception_info:
134+
SelectRequester(
135+
install=self.install,
136+
project_slug=self.project.slug,
137+
uri="/get-issues",
138+
).run()
139+
assert (
140+
str(exception_info.value)
141+
== f"Something went wrong while getting SelectFields from {self.sentry_app.slug}"
142+
)
143+
144+
@responses.activate
145+
def test_validation_error_message_validator(self):
146+
uri = "/get-issues"
147+
148+
responses.add(
149+
method=responses.GET,
150+
url=f"https://example.com/get-issues?installationId={self.install.uuid}&projectSlug={self.project.slug}",
151+
json={},
152+
status=200,
153+
)
154+
155+
with pytest.raises(ValidationError) as exception_info:
156+
SelectRequester(
157+
install=self.install,
158+
project_slug=self.project.slug,
159+
uri=uri,
160+
).run()
161+
162+
assert (
163+
str(exception_info.value)
164+
== f"Invalid response format for SelectField in {self.sentry_app.slug} from uri: {uri}"
165+
)
166+
167+
@responses.activate
168+
def test_validation_error_message_missing_field(self):
169+
responses.add(
170+
method=responses.GET,
171+
url=f"https://example.com/get-issues?installationId={self.install.uuid}&projectSlug={self.project.slug}",
172+
json=[{"bruh": "bruhhhhh"}],
173+
status=200,
174+
)
175+
176+
with pytest.raises(ValidationError) as exception_info:
177+
SelectRequester(
178+
install=self.install,
179+
project_slug=self.project.slug,
180+
uri="/get-issues",
181+
).run()
182+
183+
assert (
184+
str(exception_info.value) == "Missing `value` or `label` in option data for SelectField"
185+
)

0 commit comments

Comments
 (0)