mirror of
https://github.com/fusion44/blitz_api.git
synced 2026-08-13 11:52:45 +02:00
Bitcoin Core returns the -28 warmup error ('Loading block index',
'Verifying blocks', 'Starting network threads') as an HTTP 200 response
with a JSON-RPC error body. _process_response only classified errors on
the non-200 path and passed a 200 body through unchanged, so the result
had an 'error' key but no 'status' key. Callers doing
'raise HTTPException(result["status"], ...)' then crashed with
KeyError: 'status' instead of HTTPException(425), so the startup
warmup-retry loop in initialize_bitcoin_repo never engaged and the API
(and login) failed while bitcoind was still warming up.
Same root cause, different -28 warmup message.
Fixes #287
Fixes #285
Normalize any JSON-RPC error to an {error, status} dict regardless of the
HTTP status, mapping the warmup messages to 425 TOO_EARLY as before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
57 lines
1.5 KiB
Python
57 lines
1.5 KiB
Python
"""
|
|
Regression test for blitz_api#287.
|
|
|
|
Bitcoin Core returns the -28 "Loading block index" warmup error as an
|
|
HTTP 200 with a JSON-RPC error body. _process_response returned that body
|
|
unchanged, so it had an "error" key but no "status" key, and callers doing
|
|
`raise HTTPException(result["status"], ...)` crashed with KeyError: 'status'
|
|
instead of the HTTPException(425) the startup warmup loop expects.
|
|
"""
|
|
|
|
import pytest
|
|
from starlette import status
|
|
|
|
from app.bitcoind.utils import _process_response
|
|
|
|
|
|
class _FakeResp:
|
|
def __init__(self, http_status, body, reason="OK"):
|
|
self.status = http_status
|
|
self._body = body
|
|
self.reason = reason
|
|
|
|
async def json(self):
|
|
return self._body
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"message",
|
|
[
|
|
"Loading block index…", # blitz_api#287
|
|
"Verifying blocks…", # blitz_api#285
|
|
"Starting network threads…",
|
|
],
|
|
)
|
|
async def test_200_warmup_error_is_normalized_to_too_early(message):
|
|
resp = _FakeResp(
|
|
status.HTTP_200_OK,
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"error": {"code": -28, "message": message},
|
|
"id": 6,
|
|
},
|
|
)
|
|
|
|
out = await _process_response(resp)
|
|
|
|
assert out["status"] == status.HTTP_425_TOO_EARLY
|
|
assert out["error"] # a human-readable message, not the raw dict
|
|
|
|
|
|
async def test_200_success_body_is_passed_through():
|
|
body = {"jsonrpc": "2.0", "result": {"blocks": 42}, "error": None, "id": 1}
|
|
resp = _FakeResp(status.HTTP_200_OK, body)
|
|
|
|
out = await _process_response(resp)
|
|
|
|
assert out == body
|