Files
ai-exchange/tests/unit/test_monitoring_alert_rollout.py
T
2026-05-11 23:37:47 +08:00

164 lines
8.2 KiB
Python

import os
import unittest
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://user:pass@localhost:5432/ai_ict_test")
from scripts import run_monitoring_alert_rollout
class MonitoringAlertRolloutTests(unittest.TestCase):
def test_seed_rollout_env_uses_env_example_database_url_when_missing(self) -> None:
original_env_local_path = run_monitoring_alert_rollout.ENV_LOCAL_PATH
original_env_path = run_monitoring_alert_rollout.ENV_PATH
original_env_example_path = run_monitoring_alert_rollout.ENV_EXAMPLE_PATH
try:
run_monitoring_alert_rollout.ENV_LOCAL_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.local.does-not-exist")
run_monitoring_alert_rollout.ENV_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.does-not-exist")
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.example")
seeded = run_monitoring_alert_rollout._seed_rollout_env({})
finally:
run_monitoring_alert_rollout.ENV_LOCAL_PATH = original_env_local_path
run_monitoring_alert_rollout.ENV_PATH = original_env_path
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = original_env_example_path
self.assertIn("DATABASE_URL", seeded)
self.assertIn("postgresql+psycopg://postgres:postgres@localhost:5432/ai_ict", seeded["DATABASE_URL"])
def test_seed_rollout_env_prefers_env_local_database_url(self) -> None:
original_env_local_path = run_monitoring_alert_rollout.ENV_LOCAL_PATH
original_env_path = run_monitoring_alert_rollout.ENV_PATH
original_env_example_path = run_monitoring_alert_rollout.ENV_EXAMPLE_PATH
try:
run_monitoring_alert_rollout.ENV_LOCAL_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.example")
run_monitoring_alert_rollout.ENV_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.does-not-exist")
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.does-not-exist")
seeded = run_monitoring_alert_rollout._seed_rollout_env({})
finally:
run_monitoring_alert_rollout.ENV_LOCAL_PATH = original_env_local_path
run_monitoring_alert_rollout.ENV_PATH = original_env_path
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = original_env_example_path
self.assertIn("DATABASE_URL", seeded)
self.assertIn("postgresql+psycopg://postgres:postgres@localhost:5432/ai_ict", seeded["DATABASE_URL"])
def test_seed_rollout_env_prefers_local_components_over_env_example_url(self) -> None:
original_env_local_path = run_monitoring_alert_rollout.ENV_LOCAL_PATH
original_env_path = run_monitoring_alert_rollout.ENV_PATH
original_env_example_path = run_monitoring_alert_rollout.ENV_EXAMPLE_PATH
try:
local_path = run_monitoring_alert_rollout.Path("D:/ai-exchange/.tmp_rollout_local_env")
local_path.write_text(
"DATABASE_HOST=192.168.3.90\n"
"DATABASE_PORT=5432\n"
"DATABASE_NAME=ai_ict\n"
"DATABASE_USER=yuqei\n"
"DATABASE_PASSWORD=abc123\n",
encoding="utf-8",
)
run_monitoring_alert_rollout.ENV_LOCAL_PATH = local_path
run_monitoring_alert_rollout.ENV_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.does-not-exist")
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.example")
seeded = run_monitoring_alert_rollout._seed_rollout_env({})
finally:
if 'local_path' in locals() and local_path.exists():
local_path.unlink()
run_monitoring_alert_rollout.ENV_LOCAL_PATH = original_env_local_path
run_monitoring_alert_rollout.ENV_PATH = original_env_path
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = original_env_example_path
self.assertEqual(
seeded["DATABASE_URL"],
"postgresql+psycopg://yuqei:abc123@192.168.3.90:5432/ai_ict",
)
def test_seed_rollout_env_prefers_monitoring_alert_overrides(self) -> None:
seeded = run_monitoring_alert_rollout._seed_rollout_env(
{
"MONITORING_ALERT_DATABASE_URL": "postgresql+psycopg://remote-user:pw@192.168.3.90:5432/ai_ict",
"MONITORING_ALERT_BROKER_READ_PROXY_URL": "http://192.168.3.73:10808",
"MONITORING_ALERT_OKX_API_KEY": "k",
"MONITORING_ALERT_OKX_API_SECRET": "s",
"MONITORING_ALERT_OKX_API_PASSPHRASE": "p",
}
)
self.assertEqual(seeded["DATABASE_URL"], "postgresql+psycopg://remote-user:pw@192.168.3.90:5432/ai_ict")
self.assertEqual(seeded["BROKER_READ_PROXY_URL"], "http://192.168.3.73:10808")
self.assertEqual(seeded["OKX_API_KEY"], "k")
self.assertEqual(seeded["OKX_API_SECRET"], "s")
self.assertEqual(seeded["OKX_API_PASSPHRASE"], "p")
def test_seed_rollout_env_composes_database_url_from_components(self) -> None:
original_env_local_path = run_monitoring_alert_rollout.ENV_LOCAL_PATH
original_env_path = run_monitoring_alert_rollout.ENV_PATH
original_env_example_path = run_monitoring_alert_rollout.ENV_EXAMPLE_PATH
try:
missing = run_monitoring_alert_rollout.Path("D:/ai-exchange/.env.does-not-exist")
run_monitoring_alert_rollout.ENV_LOCAL_PATH = missing
run_monitoring_alert_rollout.ENV_PATH = missing
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = missing
seeded = run_monitoring_alert_rollout._seed_rollout_env(
{
"DATABASE_URL": "",
"MONITORING_ALERT_DATABASE_HOST": "192.168.3.90",
"MONITORING_ALERT_DATABASE_PORT": "5432",
"MONITORING_ALERT_DATABASE_NAME": "ai_ict",
"MONITORING_ALERT_DATABASE_USER": "yuqei",
"MONITORING_ALERT_DATABASE_PASSWORD": "abc123",
}
)
finally:
run_monitoring_alert_rollout.ENV_LOCAL_PATH = original_env_local_path
run_monitoring_alert_rollout.ENV_PATH = original_env_path
run_monitoring_alert_rollout.ENV_EXAMPLE_PATH = original_env_example_path
self.assertEqual(
seeded["DATABASE_URL"],
"postgresql+psycopg://yuqei:abc123@192.168.3.90:5432/ai_ict",
)
def test_detect_major_blocker_classifies_missing_database_url_as_runtime_env_missing(self) -> None:
run = {
"stdout": "",
"stderr": "ValidationError: 1 validation error for Settings\ndatabase_url\n Field required [type=missing, input_value={}, input_type=dict]",
}
blocker = run_monitoring_alert_rollout._detect_major_blocker(run)
self.assertEqual(blocker, "runtime_env_missing")
def test_finalize_phase_result_downgrades_runtime_exit_with_blockers_to_needs_work(self) -> None:
phase = {"code": "N4", "tasks": ["N4-1"], "files": ["src/services/runtime/trading_runtime_service.py"], "validation_commands": ["cmd"]}
phase_result = {
"phase": "N4",
"title": "title",
"goal": "goal",
"started_ts": "t1",
"finished_ts": "t2",
"result": "needs_work",
"blocker": None,
"summary": "old",
"tasks": ["N4-1"],
"files": ["src/services/runtime/trading_runtime_service.py"],
"commands": [
{
"command": "cmd",
"returncode": 2,
"stdout": "Trading runtime: running / stopped\nBlockers: market_stream_degraded",
"stderr": "",
}
],
"deliverables": [],
"failed_command": "cmd",
}
result = run_monitoring_alert_rollout._finalize_phase_result(phase=phase, phase_result=phase_result)
self.assertEqual(result["result"], "needs_work")
self.assertIsNone(result["blocker"])
self.assertIn("Validation failed for phase N4", result["summary"])
if __name__ == "__main__":
unittest.main()