fix: handle unique constraint violation in manual fetch endpoint

When a duplicate timestamp occurs (rare but possible), return the
existing record instead of failing with a 500 error. This matches
the worker's ON CONFLICT DO NOTHING behavior.

Added test for duplicate timestamp handling.
This commit is contained in:
counterweight 2025-12-22 16:09:05 +01:00
parent 1c9761e559
commit a5488fd20b
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
2 changed files with 48 additions and 2 deletions

View file

@ -241,6 +241,39 @@ class TestManualFetch:
assert len(data) == 1
assert data[0]["price"] == 87654.32
@pytest.mark.asyncio
async def test_returns_existing_record_on_duplicate_timestamp(
self, client_factory, admin_user
):
"""Verify duplicate timestamp returns existing record instead of error."""
fixed_timestamp = datetime(2024, 1, 15, 12, 0, 0, tzinfo=UTC)
# Seed an existing record with the same timestamp we'll get from the mock
async with client_factory.get_db_session() as db:
existing = PriceHistory(
source=SOURCE_BITFINEX,
pair=PAIR_BTC_EUR,
price=90000.0,
timestamp=fixed_timestamp,
)
db.add(existing)
await db.commit()
await db.refresh(existing)
existing_id = existing.id
# Mock fetch_btc_eur_price to return the same timestamp
with patch("routes.audit.fetch_btc_eur_price") as mock_fetch:
mock_fetch.return_value = (95000.0, fixed_timestamp)
async with client_factory.create(cookies=admin_user["cookies"]) as authed:
response = await authed.post("/api/audit/price-history/fetch")
# Should succeed and return the existing record
assert response.status_code == 200
data = response.json()
assert data["id"] == existing_id
assert data["price"] == 90000.0 # Original price, not the new one
def create_mock_pool(mock_conn: AsyncMock) -> MagicMock:
"""Create a mock asyncpg pool with proper async context manager behavior."""