Files
ai-exchange/tests/unit/test_launch_readiness_service.py
T
2026-05-08 21:01:09 +08:00

118 lines
4.0 KiB
Python

import os
import unittest
from unittest.mock import patch
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://user:pass@localhost:5432/ai_ict_test")
from src.services.readiness import LaunchReadinessService
class LaunchReadinessServiceTests(unittest.TestCase):
def test_build_summary_reports_assisted_not_ready_without_real_trade_sample(self) -> None:
service = LaunchReadinessService(
market_state_service=_MarketStateService(),
broker_read_model_service=_BrokerReadService(),
weekly_review_service=_WeeklyReviewService(),
trust_service=_TrustService(),
live_readiness_service=_LiveReadinessService(),
)
with patch("src.services.readiness.launch_readiness_service.get_trading_runtime_service", return_value=_RuntimeService()):
payload = service.build_summary(instrument_id=1, timeframe="1m")
self.assertTrue(payload["analysis_only_ready"])
self.assertTrue(payload["assisted_trading_ready"])
self.assertFalse(payload["real_trade_loop_ready"])
self.assertIn("real_trade_sample_verified", payload["warning_reasons"])
self.assertFalse(payload["real_live_ready"])
def test_build_summary_keeps_decision_support_false_when_only_blacklist_models_exist(self) -> None:
service = LaunchReadinessService(
market_state_service=_MarketStateService(),
broker_read_model_service=_BrokerReadService(),
weekly_review_service=_WeeklyReviewService(),
trust_service=_BlacklistOnlyTrustService(),
live_readiness_service=_LiveReadinessService(),
)
with patch("src.services.readiness.launch_readiness_service.get_trading_runtime_service", return_value=_RuntimeService()):
payload = service.build_summary(instrument_id=1, timeframe="1m")
self.assertTrue(payload["analysis_only_ready"])
self.assertFalse(payload["decision_support_ready"])
self.assertIn("trust_model_available", payload["warning_reasons"])
class _MarketState:
freshness = type("Freshness", (), {"code": "market_data_fresh"})()
stream_state = type("Stream", (), {"code": "market_stream_connected"})()
data_gap_state = type("Gap", (), {"code": "market_data_gap_clear"})()
news_window = type("News", (), {"provider_name": "cached", "freshness_code": "news_provider_cached", "error": None})()
def to_dict(self):
return {
"freshness": {"code": "market_data_fresh"},
"stream_state": {"code": "market_stream_connected"},
"data_gap_state": {"code": "market_data_gap_clear"},
}
class _MarketStateService:
def build_market_state(self, **kwargs):
return _MarketState()
class _BrokerState:
status = "broker_state_ok"
def to_dict(self):
return {"status": "broker_state_ok"}
class _BrokerReadService:
def fetch_snapshot(self, **kwargs):
return _BrokerState()
class _WeeklyReviewService:
def build_summary(self, **kwargs):
return {"real_trade_count": 0}
class _TrustService:
def build_summary(self, **kwargs):
return {
"whitelist": ["OSOK"],
"observe_list": [],
"blacklist": [],
"analysis_only_list": ["OSOK"],
"decision_support_list": ["OSOK"],
"execution_candidate_list": ["OSOK"],
}
class _BlacklistOnlyTrustService:
def build_summary(self, **kwargs):
return {
"whitelist": [],
"observe_list": [],
"blacklist": ["SWEEP_MSS_FVG"],
"analysis_only_list": ["SWEEP_MSS_FVG"],
"decision_support_list": [],
"execution_candidate_list": [],
}
class _LiveReadinessService:
def build_summary(self, **kwargs):
return {"ready_for_real_live": False, "blocking_reasons": ["adapter_real_live_not_ready"]}
class _RuntimeService:
def status(self):
return {"scheduler_state": "running", "current_blockers": []}
if __name__ == "__main__":
unittest.main()