import pytest import pytest_asyncio from decimal import Decimal from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker from app.models.entities import Base, LedgerEntryType from app.domains.ledger.service import LedgerService, InsufficientBalanceError TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:" @pytest_asyncio.fixture async def test_session(): engine = create_async_engine(TEST_DATABASE_URL, echo=False) async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) session_maker = async_sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) async with session_maker() as session: yield session async with engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all) await engine.dispose() @pytest.mark.asyncio async def test_ledger_deposit_flow(test_session: AsyncSession): ledger = LedgerService(test_session) user = "0x6cddF384792C77219fc25C454Cfe264757842830" # 1. 初始余额为 0 bal = await ledger.get_or_create_balance(user) assert bal.available_balance == Decimal("0") # 2. 存入 1000 WUSD entry = await ledger.record_deposit(user, Decimal("1000"), "0xtx1") assert entry.entry_type == LedgerEntryType.DEPOSIT assert entry.amount == Decimal("1000") assert entry.balance_after == Decimal("1000") bal = await ledger.get_or_create_balance(user) assert bal.available_balance == Decimal("1000") @pytest.mark.asyncio async def test_ledger_trade_and_insufficient_balance(test_session: AsyncSession): ledger = LedgerService(test_session) user = "0x6cddF384792C77219fc25C454Cfe264757842830" # 充值 500 WUSD await ledger.record_deposit(user, Decimal("500"), "0xtx1") # 尝试买入 600 WUSD (超额报错) with pytest.raises(InsufficientBalanceError): await ledger.record_trade( address=user, market_address="0xmarket1", order_id="order_1", side="BUY", amount=Decimal("600"), fee=Decimal("3.6") ) # 成功买入 100 WUSD (扣除 100 + 0.6 手续费) entry = await ledger.record_trade( address=user, market_address="0xmarket1", order_id="order_2", side="BUY", amount=Decimal("100"), fee=Decimal("0.6") ) assert entry.entry_type == LedgerEntryType.TRADE_BUY assert entry.amount == Decimal("-100.6") assert entry.balance_after == Decimal("399.4") # 验证不可变流水历史条数 history = await ledger.list_user_ledger(user) assert len(history) == 2