164 lines
8.2 KiB
Python
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()
|