122 lines
3.8 KiB
Python
122 lines
3.8 KiB
Python
"""Tests for OpenAPI partial-data fallback in price collectors."""
|
|
from datetime import date
|
|
from unittest.mock import patch
|
|
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
from sqlalchemy.pool import StaticPool
|
|
|
|
from app.core.database import Base
|
|
from app.models.stock import AssetClass, ETF, Price, Stock
|
|
from app.services.collectors.etf_price_collector import ETFPriceCollector
|
|
from app.services.collectors.price_collector import PriceCollector
|
|
|
|
|
|
def make_db():
|
|
engine = create_engine(
|
|
"sqlite:///:memory:",
|
|
connect_args={"check_same_thread": False},
|
|
poolclass=StaticPool,
|
|
)
|
|
Base.metadata.create_all(bind=engine)
|
|
Session = sessionmaker(bind=engine)
|
|
session = Session()
|
|
return session, engine
|
|
|
|
|
|
def test_price_collector_falls_back_when_openapi_misses_end_date():
|
|
db, engine = make_db()
|
|
try:
|
|
db.add(
|
|
Stock(
|
|
ticker="005930",
|
|
name="Samsung Electronics",
|
|
market="KOSPI",
|
|
base_date=date(2026, 5, 15),
|
|
)
|
|
)
|
|
db.add(
|
|
Price(
|
|
ticker="005930",
|
|
date=date(2026, 5, 14),
|
|
open=70000,
|
|
high=71000,
|
|
low=69000,
|
|
close=70500,
|
|
volume=1000,
|
|
)
|
|
)
|
|
db.commit()
|
|
|
|
with patch("app.services.collectors.price_collector.get_krx_client", return_value=object()), \
|
|
patch.object(PriceCollector, "_collect_openapi", return_value=1), \
|
|
patch.object(PriceCollector, "_collect_pykrx", return_value=1) as mock_pykrx:
|
|
total = PriceCollector(db, start_date="20260514", end_date="20260515").collect()
|
|
|
|
assert total == 1
|
|
mock_pykrx.assert_called_once()
|
|
finally:
|
|
db.close()
|
|
Base.metadata.drop_all(bind=engine)
|
|
|
|
|
|
def test_price_collector_skips_fallback_when_openapi_has_end_date():
|
|
db, engine = make_db()
|
|
try:
|
|
db.add(
|
|
Stock(
|
|
ticker="005930",
|
|
name="Samsung Electronics",
|
|
market="KOSPI",
|
|
base_date=date(2026, 5, 15),
|
|
)
|
|
)
|
|
db.add(
|
|
Price(
|
|
ticker="005930",
|
|
date=date(2026, 5, 15),
|
|
open=70000,
|
|
high=71000,
|
|
low=69000,
|
|
close=70500,
|
|
volume=1000,
|
|
)
|
|
)
|
|
db.commit()
|
|
|
|
with patch("app.services.collectors.price_collector.get_krx_client", return_value=object()), \
|
|
patch.object(PriceCollector, "_collect_openapi", return_value=1), \
|
|
patch.object(PriceCollector, "_collect_pykrx", return_value=1) as mock_pykrx:
|
|
total = PriceCollector(db, start_date="20260514", end_date="20260515").collect()
|
|
|
|
assert total == 1
|
|
mock_pykrx.assert_not_called()
|
|
finally:
|
|
db.close()
|
|
Base.metadata.drop_all(bind=engine)
|
|
|
|
|
|
def test_etf_price_collector_falls_back_when_openapi_returns_zero():
|
|
db, engine = make_db()
|
|
try:
|
|
db.add(
|
|
ETF(
|
|
ticker="069500",
|
|
name="KODEX 200",
|
|
asset_class=AssetClass.EQUITY,
|
|
market="KOSPI",
|
|
)
|
|
)
|
|
db.commit()
|
|
|
|
with patch("app.services.collectors.etf_price_collector.get_krx_client", return_value=object()), \
|
|
patch.object(ETFPriceCollector, "_collect_openapi", return_value=0), \
|
|
patch.object(ETFPriceCollector, "_collect_pykrx", return_value=1) as mock_pykrx:
|
|
total = ETFPriceCollector(db, start_date="20260515", end_date="20260515").collect()
|
|
|
|
assert total == 1
|
|
mock_pykrx.assert_called_once()
|
|
finally:
|
|
db.close()
|
|
Base.metadata.drop_all(bind=engine)
|