- Remove EUR_TRADE_MIN, EUR_TRADE_MAX, PREMIUM_PERCENTAGE from shared_constants.py - Remove eurTradeMin, eurTradeMax, premiumPercentage from shared/constants.json - Update validate_constants.py to not require removed fields - Update seed.py and seed_e2e.py to use defaults if fields don't exist - Update tests to handle missing constants gracefully
262 lines
10 KiB
Python
262 lines
10 KiB
Python
"""
|
|
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
|