""" 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