Skip to content

Commit 539204f

Browse files
fix(ofrep): handle 401, 403, 404 and 5xx errors explicitly and add tests
Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
1 parent 80da6b9 commit 539204f

2 files changed

Lines changed: 74 additions & 3 deletions

File tree

providers/openfeature-provider-ofrep/src/openfeature/contrib/provider/ofrep/__init__.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,23 @@ def _handle_error(self, exception: requests.RequestException) -> NoReturn:
183183
f"Rate limited, retry after: {retry_after}"
184184
) from exception
185185

186+
if response.status_code == 401:
187+
raise OpenFeatureError(ErrorCode.GENERAL, "unauthorized") from exception
188+
189+
if response.status_code == 403:
190+
raise OpenFeatureError(ErrorCode.GENERAL, "forbidden") from exception
191+
192+
if response.status_code == 404:
193+
try:
194+
data = response.json()
195+
error_details = data["errorDetails"]
196+
except JSONDecodeError:
197+
error_details = response.text
198+
raise FlagNotFoundError(error_details) from exception
199+
200+
if response.status_code > 400:
201+
raise OpenFeatureError(ErrorCode.GENERAL, response.text) from exception
202+
186203
try:
187204
data = response.json()
188205
except JSONDecodeError:
@@ -191,9 +208,6 @@ def _handle_error(self, exception: requests.RequestException) -> NoReturn:
191208
error_code = ErrorCode(data["errorCode"])
192209
error_details = data["errorDetails"]
193210

194-
if response.status_code == 404:
195-
raise FlagNotFoundError(error_details) from exception
196-
197211
if error_code == ErrorCode.PARSE_ERROR:
198212
raise ParseError(error_details) from exception
199213
if error_code == ErrorCode.TARGETING_KEY_MISSING:

providers/openfeature-provider-ofrep/tests/test_provider.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
from openfeature.contrib.provider.ofrep import OFREPProvider
44
from openfeature.evaluation_context import EvaluationContext
55
from openfeature.exception import (
6+
ErrorCode,
67
FlagNotFoundError,
78
GeneralError,
89
InvalidContextError,
10+
OpenFeatureError,
911
ParseError,
1012
TypeMismatchError,
1113
)
@@ -83,6 +85,61 @@ def test_provider_flag_not_found(ofrep_provider, requests_mock):
8385
ofrep_provider.resolve_boolean_details("flag_key", False)
8486

8587

88+
def test_provider_unauthorized(ofrep_provider, requests_mock):
89+
requests_mock.post(
90+
"http://localhost:8080/ofrep/v1/evaluate/flags/flag_key",
91+
status_code=401,
92+
text="unauthorized",
93+
)
94+
95+
with pytest.raises(OpenFeatureError) as exc_info:
96+
ofrep_provider.resolve_boolean_details("flag_key", False)
97+
98+
assert exc_info.value.error_code == ErrorCode.GENERAL
99+
assert exc_info.value.error_message == "unauthorized"
100+
101+
102+
def test_provider_forbidden(ofrep_provider, requests_mock):
103+
requests_mock.post(
104+
"http://localhost:8080/ofrep/v1/evaluate/flags/flag_key",
105+
status_code=403,
106+
text="forbidden",
107+
)
108+
109+
with pytest.raises(OpenFeatureError) as exc_info:
110+
ofrep_provider.resolve_boolean_details("flag_key", False)
111+
112+
assert exc_info.value.error_code == ErrorCode.GENERAL
113+
assert exc_info.value.error_message == "forbidden"
114+
115+
116+
def test_provider_flag_not_found_invalid_json(ofrep_provider, requests_mock):
117+
"""Test 404 with non-JSON response falls back to response text for error details"""
118+
requests_mock.post(
119+
"http://localhost:8080/ofrep/v1/evaluate/flags/flag_key",
120+
status_code=404,
121+
text="Flag not found - plain text response",
122+
)
123+
124+
with pytest.raises(FlagNotFoundError, match="Flag not found - plain text response"):
125+
ofrep_provider.resolve_boolean_details("flag_key", False)
126+
127+
128+
def test_provider_server_error(ofrep_provider, requests_mock):
129+
"""Test generic OpenFeatureError for status codes > 400 (e.g. 500, 502)"""
130+
requests_mock.post(
131+
"http://localhost:8080/ofrep/v1/evaluate/flags/flag_key",
132+
status_code=500,
133+
text="Internal Server Error",
134+
)
135+
136+
with pytest.raises(OpenFeatureError) as exc_info:
137+
ofrep_provider.resolve_boolean_details("flag_key", False)
138+
139+
assert exc_info.value.error_code == ErrorCode.GENERAL
140+
assert exc_info.value.error_message == "Internal Server Error"
141+
142+
86143
def test_provider_invalid_context(ofrep_provider, requests_mock):
87144
requests_mock.post(
88145
"http://localhost:8080/ofrep/v1/evaluate/flags/flag_key",

0 commit comments

Comments
 (0)