test: add unit tests for scheduled Bitcoin price job handler
This commit is contained in:
parent
cd2285395d
commit
9db43c474e
2 changed files with 121 additions and 21 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""Tests for price history feature."""
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
|
|
@ -7,6 +8,7 @@ import pytest
|
|||
|
||||
from models import PriceHistory
|
||||
from price_fetcher import fetch_btc_eur_price
|
||||
from worker import process_bitcoin_price_job
|
||||
|
||||
|
||||
class TestFetchBtcEurPrice:
|
||||
|
|
@ -238,3 +240,91 @@ class TestManualFetch:
|
|||
data = response.json()
|
||||
assert len(data) == 1
|
||||
assert data[0]["price"] == 87654.32
|
||||
|
||||
|
||||
def create_mock_pool(mock_conn: AsyncMock) -> MagicMock:
|
||||
"""Create a mock asyncpg pool with proper async context manager behavior."""
|
||||
mock_pool = MagicMock()
|
||||
|
||||
@asynccontextmanager
|
||||
async def mock_acquire():
|
||||
yield mock_conn
|
||||
|
||||
mock_pool.acquire = mock_acquire
|
||||
return mock_pool
|
||||
|
||||
|
||||
class TestProcessBitcoinPriceJob:
|
||||
"""Tests for the scheduled Bitcoin price job handler."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stores_price_on_success(self):
|
||||
"""Verify price is stored in database on successful fetch."""
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = [0, 0, 0, 0, 0, 0, 95000.0, 0, 0, 0]
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
|
||||
mock_http_client = AsyncMock()
|
||||
mock_http_client.get.return_value = mock_response
|
||||
mock_http_client.__aenter__.return_value = mock_http_client
|
||||
mock_http_client.__aexit__.return_value = None
|
||||
|
||||
mock_conn = AsyncMock()
|
||||
mock_pool = create_mock_pool(mock_conn)
|
||||
|
||||
with patch("price_fetcher.httpx.AsyncClient", return_value=mock_http_client):
|
||||
await process_bitcoin_price_job(mock_pool)
|
||||
|
||||
# Verify execute was called with correct values
|
||||
mock_conn.execute.assert_called_once()
|
||||
call_args = mock_conn.execute.call_args
|
||||
|
||||
# Check the SQL parameters
|
||||
assert call_args[0][1] == "bitfinex" # source
|
||||
assert call_args[0][2] == "BTC/EUR" # pair
|
||||
assert call_args[0][3] == 95000.0 # price
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fails_silently_on_api_error(self):
|
||||
"""Verify no exception is raised and no DB insert on API error."""
|
||||
import httpx
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.raise_for_status.side_effect = httpx.HTTPStatusError(
|
||||
"Server Error", request=MagicMock(), response=MagicMock()
|
||||
)
|
||||
|
||||
mock_http_client = AsyncMock()
|
||||
mock_http_client.get.return_value = mock_response
|
||||
mock_http_client.__aenter__.return_value = mock_http_client
|
||||
mock_http_client.__aexit__.return_value = None
|
||||
|
||||
mock_conn = AsyncMock()
|
||||
mock_pool = create_mock_pool(mock_conn)
|
||||
|
||||
with patch("price_fetcher.httpx.AsyncClient", return_value=mock_http_client):
|
||||
# Should not raise an exception
|
||||
await process_bitcoin_price_job(mock_pool)
|
||||
|
||||
# Should not have called execute
|
||||
mock_conn.execute.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fails_silently_on_db_error(self):
|
||||
"""Verify no exception is raised on database error."""
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = [0, 0, 0, 0, 0, 0, 95000.0, 0, 0, 0]
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
|
||||
mock_http_client = AsyncMock()
|
||||
mock_http_client.get.return_value = mock_response
|
||||
mock_http_client.__aenter__.return_value = mock_http_client
|
||||
mock_http_client.__aexit__.return_value = None
|
||||
|
||||
mock_conn = AsyncMock()
|
||||
mock_conn.execute.side_effect = Exception("Database connection error")
|
||||
mock_pool = create_mock_pool(mock_conn)
|
||||
|
||||
with patch("price_fetcher.httpx.AsyncClient", return_value=mock_http_client):
|
||||
# Should not raise an exception
|
||||
await process_bitcoin_price_job(mock_pool)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue