"""portfolio_cache_bridge: 매매 엔진 체결 → 포트폴리오 캐시/Portfolio 즉시 반영.""" import asyncio from decimal import Decimal from unittest.mock import AsyncMock, patch import pytest from app.api.endpoints.portfolio import portfolio_cache from app.models.models import Portfolio from app.services import portfolio_cache_bridge as bridge @pytest.fixture(autouse=True) def _reset_cache(): portfolio_cache.holdings = [] portfolio_cache.summary = {"available_cash": 1_000_000, "total_value": 0, "total_investment": 0, "total_assets": 1_000_000, "total_profit_loss": 0, "total_profit_loss_rate": 0, "total_stocks": 0} portfolio_cache.recent_sells = {} yield @pytest.mark.asyncio async def test_reflect_buy_then_sell_updates_cache_and_queues_db(): q = AsyncMock() with patch("app.services.db_worker.enqueue_portfolio_upsert", q): await bridge.reflect_buy("005930", "삼성전자", 3, 70000.0, strategy_type="daytrading") h = portfolio_cache.holdings[0] assert (h.stock_code, h.quantity, h.strategy_type) == ("005930", 3, "daytrading") assert portfolio_cache.summary["available_cash"] == 1_000_000 - 210_000 assert q.await_args.args[0]["strategy_type"] == "daytrading" # 부분 매도 → 잔량 반영, 전량 매도 → 목록에서 제거 + 최근매도 기록(동기화 되살림 방지) with patch("app.services.db_worker.enqueue_portfolio_upsert", q): await bridge.reflect_sell("005930", 1, 71000.0, remaining_qty=2) assert portfolio_cache.holdings[0].quantity == 2 await bridge.reflect_sell("005930", 2, 71000.0, remaining_qty=0) assert portfolio_cache.holdings == [] assert q.await_args.args[0]["quantity"] == 0 assert portfolio_cache.recently_sold_qty("005930") == 2 @pytest.mark.asyncio async def test_reflect_sell_unknown_holding_does_not_zero_db(): """캐시에 없고 잔량도 모르면 DB 수량을 0으로 덮어쓰지 않는다.""" q = AsyncMock() with patch("app.services.db_worker.enqueue_portfolio_upsert", q): await bridge.reflect_sell("000660", 5, 100000.0) q.assert_not_awaited()