Skip to content

Commit 5407535

Browse files
fix: improve assert validations
1 parent d430975 commit 5407535

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

biothings/web/query/formatter.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,26 @@ class ESResultFormatter(ResultFormatter):
8484
class _Hits(Hits):
8585
def __init__(self, *args, **kwargs):
8686
super().__init__(*args, **kwargs)
87+
# Check if this is an error response from Elasticsearch
88+
if "error" in self.data:
89+
logger.error("ES returned error response: %s", self.data)
90+
raise ValueError("Invalid response format")
91+
8792
# make sure the document is coming from
8893
# elasticsearch at initialization time
89-
assert "hits" in self.data
90-
assert "total" in self.data["hits"]
91-
assert "hits" in self.data["hits"]
94+
if "hits" not in self.data:
95+
logger.error("ES response missing 'hits' field. Response data: %s", self.data)
96+
raise ValueError("Response missing 'hits' field")
97+
if "total" not in self.data["hits"]:
98+
logger.error("ES response missing 'hits.total' field. Response data: %s", self.data)
99+
raise ValueError("Response missing 'hits.total' field")
100+
if "hits" not in self.data["hits"]:
101+
logger.error("ES response missing 'hits.hits' field. Response data: %s", self.data)
102+
raise ValueError("Response missing 'hits.hits' field")
92103
for hit in self.data["hits"]["hits"]:
93-
assert "_source" in hit
104+
if "_source" not in hit:
105+
logger.error("ES hit missing '_source' field. Hit data: %s", hit)
106+
raise ValueError("Hit missing '_source' field")
94107

95108
class _Doc(Doc):
96109
pass

biothings/web/query/pipeline.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ async def _(*args, **kwargs):
147147
elif error_type == "index_not_found_exception":
148148
raise QueryPipelineException(500, error_type)
149149

150+
elif error_type == "es_rejected_execution_exception":
151+
# ES cluster is overloaded, all thread pools at capacity
152+
raise QueryPipelineException(503, "Service Unavailable", "Elasticsearch cluster overloaded")
153+
150154
else: # unexpected
151155
raise
152156

tests/web/test_es_exceptions.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ async def func():
160160

161161

162162
@pytest.mark.asyncio
163-
async def test_generic_exception():
163+
async def test_index_not_found_exception():
164164
@capturesESExceptions
165165
async def func():
166-
exc = Exception(message="test_generic_exception", meta={}, body={})
166+
exc = Exception(message="test_index_not_found_exception", meta={}, body={})
167167
exc.status_code = 500
168168
exc.info = {"error": {"type": "index_not_found_exception", "reason": "test_reason"}}
169169
raise exc
@@ -175,6 +175,22 @@ async def func():
175175
assert exc_info.value.details == "Exception() takes no keyword arguments"
176176

177177

178+
@pytest.mark.asyncio
179+
async def test_es_rejected_execution_exception():
180+
@capturesESExceptions
181+
async def func():
182+
exc = TransportError("test_es_rejected_execution_exception")
183+
exc.status_code = 503
184+
exc.info = {"error": {"type": "es_rejected_execution_exception", "reason": "rejected execution of TimedRunnable..."}}
185+
raise exc
186+
187+
with pytest.raises(QueryPipelineException) as exc_info:
188+
await func()
189+
assert exc_info.value.code == 503
190+
assert exc_info.value.summary == "Service Unavailable"
191+
assert exc_info.value.details == "Elasticsearch cluster overloaded"
192+
193+
178194
@pytest.mark.asyncio
179195
async def test_search_phase_execution_exception_rejected_execution():
180196
@capturesESExceptions

0 commit comments

Comments
 (0)