arbret/backend/tests/test_pricing_repository.py

263 lines
10 KiB
Python
Raw Permalink Normal View History

"""
Pricing Repository Tests
Tests for the pricing configuration repository.
"""
import pytest
from models import PricingConfig
from repositories.pricing import PricingRepository
class TestPricingRepository:
"""Test the PricingRepository class."""
@pytest.mark.asyncio
async def test_get_current_returns_none_when_no_config(self, client_factory):
"""get_current() returns None when no config exists."""
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
config = await repo.get_current()
assert config is None
@pytest.mark.asyncio
async def test_create_or_update_creates_first_config(self, client_factory):
"""create_or_update() creates a new config when none exists."""
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
config = await repo.create_or_update(
premium_buy=5,
premium_sell=5,
small_trade_threshold_eur=20000, # €200
small_trade_extra_premium=2,
eur_min_buy=10000, # €100
eur_max_buy=300000, # €3000
eur_min_sell=10000,
eur_max_sell=300000,
)
assert config is not None
assert config.id is not None
assert config.premium_buy == 5
assert config.premium_sell == 5
assert config.small_trade_threshold_eur == 20000
assert config.small_trade_extra_premium == 2
assert config.eur_min_buy == 10000
assert config.eur_max_buy == 300000
assert config.eur_min_sell == 10000
assert config.eur_max_sell == 300000
assert config.created_at is not None
assert config.updated_at is not None
@pytest.mark.asyncio
async def test_create_or_update_updates_existing_config(self, client_factory):
"""create_or_update() updates existing config (singleton behavior)."""
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
# Create initial config
config1 = await repo.create_or_update(
premium_buy=5,
premium_sell=5,
small_trade_threshold_eur=20000,
small_trade_extra_premium=2,
eur_min_buy=10000,
eur_max_buy=300000,
eur_min_sell=10000,
eur_max_sell=300000,
)
original_id = config1.id
original_created_at = config1.created_at
# Update config
config2 = await repo.create_or_update(
premium_buy=7,
premium_sell=6,
small_trade_threshold_eur=25000,
small_trade_extra_premium=3,
eur_min_buy=15000,
eur_max_buy=350000,
eur_min_sell=12000,
eur_max_sell=320000,
)
# Should be the same record (singleton)
assert config2.id == original_id
assert config2.created_at == original_created_at
assert config2.premium_buy == 7
assert config2.premium_sell == 6
assert config2.small_trade_threshold_eur == 25000
assert config2.small_trade_extra_premium == 3
assert config2.eur_min_buy == 15000
assert config2.eur_max_buy == 350000
assert config2.eur_min_sell == 12000
assert config2.eur_max_sell == 320000
@pytest.mark.asyncio
async def test_get_current_returns_existing_config(self, client_factory):
"""get_current() returns existing config."""
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
# Create config
created_config = await repo.create_or_update(
premium_buy=5,
premium_sell=5,
small_trade_threshold_eur=20000,
small_trade_extra_premium=2,
eur_min_buy=10000,
eur_max_buy=300000,
eur_min_sell=10000,
eur_max_sell=300000,
)
# Retrieve config
retrieved_config = await repo.get_current()
assert retrieved_config is not None
assert retrieved_config.id == created_config.id
assert retrieved_config.premium_buy == 5
assert retrieved_config.premium_sell == 5
@pytest.mark.asyncio
async def test_singleton_pattern_only_one_config_exists(self, client_factory):
"""Only one config record can exist (singleton pattern)."""
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
# Create config multiple times
config1 = await repo.create_or_update(
premium_buy=5,
premium_sell=5,
small_trade_threshold_eur=20000,
small_trade_extra_premium=2,
eur_min_buy=10000,
eur_max_buy=300000,
eur_min_sell=10000,
eur_max_sell=300000,
)
config2 = await repo.create_or_update(
premium_buy=10,
premium_sell=10,
small_trade_threshold_eur=30000,
small_trade_extra_premium=5,
eur_min_buy=20000,
eur_max_buy=400000,
eur_min_sell=20000,
eur_max_sell=400000,
)
# Should be same record
assert config1.id == config2.id
# Verify only one record exists
from sqlalchemy import select
result = await db.execute(select(PricingConfig))
all_configs = list(result.scalars().all())
assert len(all_configs) == 1
class TestPricingSeeding:
"""Test pricing configuration seeding."""
@pytest.mark.asyncio
async def test_seeding_creates_config_with_defaults(self, client_factory):
"""Seeding creates config with values from constants.json."""
import json
from pathlib import Path
# Load expected values from constants.json
constants_path = (
Path(__file__).parent.parent.parent / "shared" / "constants.json"
)
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants.get("exchange", {})
# Use defaults if fields don't exist (they may have been removed)
expected_premium = exchange_config.get("premiumPercentage", 5)
expected_min_eur = exchange_config.get("eurTradeMin", 100)
expected_max_eur = exchange_config.get("eurTradeMax", 3000)
async with client_factory.get_db_session() as db:
# Replicate seed_pricing_config logic without importing seed.py
repo = PricingRepository(db)
config = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
assert config is not None
assert config.premium_buy == expected_premium
assert config.premium_sell == expected_premium
assert config.eur_min_buy == expected_min_eur * 100
assert config.eur_max_buy == expected_max_eur * 100
assert config.eur_min_sell == expected_min_eur * 100
assert config.eur_max_sell == expected_max_eur * 100
assert config.small_trade_threshold_eur == 0
assert config.small_trade_extra_premium == 0
@pytest.mark.asyncio
async def test_re_running_seed_updates_existing_config(self, client_factory):
"""Re-running seed updates existing config instead of creating duplicate."""
import json
from pathlib import Path
constants_path = (
Path(__file__).parent.parent.parent / "shared" / "constants.json"
)
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants.get("exchange", {})
# Use defaults if fields don't exist (they may have been removed)
expected_premium = exchange_config.get("premiumPercentage", 5)
expected_min_eur = exchange_config.get("eurTradeMin", 100)
expected_max_eur = exchange_config.get("eurTradeMax", 3000)
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
# First seeding
config1 = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
original_id = config1.id
# Modify config manually
config1.premium_buy = 99
await db.commit()
# Re-run seed (update existing)
config2 = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
# Should be same record with updated values
assert config2.id == original_id
assert config2.premium_buy == expected_premium # Should be reset
assert config2.premium_buy != 99