125 lines
4.3 KiB
Python
125 lines
4.3 KiB
Python
import importlib
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
def _load_app_main(monkeypatch, *, disable_startup_tasks="1"):
|
|
monkeypatch.setenv("APP_ENV", "test")
|
|
monkeypatch.setenv("DISABLE_STARTUP_TASKS", disable_startup_tasks)
|
|
monkeypatch.setenv("DB_HOST", "localhost")
|
|
monkeypatch.setenv("DB_NAME", "trading_db")
|
|
monkeypatch.setenv("DB_USER", "trader")
|
|
monkeypatch.setenv("DB_PASSWORD", "test-password")
|
|
monkeypatch.setenv("CORS_ORIGINS", "http://localhost:3000")
|
|
monkeypatch.setenv("BROKER_TOKEN_KEY", "test-broker-token-key")
|
|
monkeypatch.setenv("RESET_OTP_SECRET", "test-reset-secret")
|
|
|
|
import app.main as app_main
|
|
|
|
importlib.reload(app_main)
|
|
return app_main
|
|
|
|
|
|
def test_liveness_succeeds_even_if_db_is_unavailable(monkeypatch):
|
|
app_main = _load_app_main(monkeypatch)
|
|
app = app_main.create_app()
|
|
|
|
import app.routers.health as health_router
|
|
|
|
monkeypatch.setattr(health_router, "health_check", lambda: False)
|
|
|
|
with TestClient(app) as client:
|
|
response = client.get("/health/live")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == {"status": "ok"}
|
|
|
|
|
|
def test_readiness_fails_when_db_is_unavailable(monkeypatch):
|
|
app_main = _load_app_main(monkeypatch)
|
|
app = app_main.create_app()
|
|
|
|
import app.routers.health as health_router
|
|
|
|
monkeypatch.setattr(health_router, "health_check", lambda: False)
|
|
|
|
with TestClient(app) as client:
|
|
response = client.get("/health/ready")
|
|
|
|
assert response.status_code == 503
|
|
assert response.json()["detail"]["db"] == "unavailable"
|
|
|
|
|
|
def test_readiness_succeeds_when_startup_complete_and_db_available(monkeypatch):
|
|
app_main = _load_app_main(monkeypatch)
|
|
app = app_main.create_app()
|
|
|
|
import app.routers.health as health_router
|
|
|
|
monkeypatch.setattr(health_router, "health_check", lambda: True)
|
|
|
|
with TestClient(app) as client:
|
|
response = client.get("/health/ready")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["status"] == "ok"
|
|
assert response.json()["startup"]["complete"] is True
|
|
|
|
|
|
def test_startup_failure_keeps_readiness_unhealthy(monkeypatch):
|
|
app_main = _load_app_main(monkeypatch, disable_startup_tasks="0")
|
|
app = app_main.create_app()
|
|
|
|
import app.routers.health as health_router
|
|
|
|
monkeypatch.setattr(health_router, "health_check", lambda: True)
|
|
|
|
def fake_startup_tasks(app):
|
|
app.state.startup_started = True
|
|
app.state.startup_complete = False
|
|
app.state.startup_error = "resume_failed"
|
|
|
|
monkeypatch.setattr(app_main, "_run_startup_tasks", fake_startup_tasks)
|
|
|
|
with TestClient(app) as client:
|
|
response = client.get("/health")
|
|
|
|
assert response.status_code == 503
|
|
assert response.json()["detail"]["startup"]["error"] == "resume_failed"
|
|
|
|
|
|
def test_production_boot_fails_without_broker_token_key(monkeypatch):
|
|
monkeypatch.setenv("APP_ENV", "production")
|
|
monkeypatch.setenv("DB_HOST", "localhost")
|
|
monkeypatch.setenv("DB_NAME", "trading_db")
|
|
monkeypatch.setenv("DB_USER", "trader")
|
|
monkeypatch.setenv("DB_PASSWORD", "test-password")
|
|
monkeypatch.setenv("CORS_ORIGINS", "https://app.quantfortune.com")
|
|
monkeypatch.setenv("RESET_OTP_SECRET", "test-reset-secret")
|
|
monkeypatch.delenv("BROKER_TOKEN_KEY", raising=False)
|
|
|
|
import app.main as app_main
|
|
|
|
with pytest.raises(RuntimeError, match="BROKER_TOKEN_KEY must be configured in production"):
|
|
importlib.reload(app_main)
|
|
|
|
|
|
def test_production_bootstrap_requires_explicit_admin_credentials(monkeypatch):
|
|
monkeypatch.setenv("APP_ENV", "production")
|
|
monkeypatch.setenv("DB_HOST", "localhost")
|
|
monkeypatch.setenv("DB_NAME", "trading_db")
|
|
monkeypatch.setenv("DB_USER", "trader")
|
|
monkeypatch.setenv("DB_PASSWORD", "test-password")
|
|
monkeypatch.setenv("CORS_ORIGINS", "https://app.quantfortune.com")
|
|
monkeypatch.setenv("RESET_OTP_SECRET", "test-reset-secret")
|
|
monkeypatch.setenv("BROKER_TOKEN_KEY", "test-broker-token-key")
|
|
monkeypatch.setenv("ENABLE_SUPER_ADMIN_BOOTSTRAP", "1")
|
|
monkeypatch.delenv("SUPER_ADMIN_EMAIL", raising=False)
|
|
monkeypatch.delenv("SUPER_ADMIN_PASSWORD", raising=False)
|
|
|
|
import app.main as app_main
|
|
|
|
with pytest.raises(RuntimeError, match="SUPER_ADMIN_EMAIL must be configured when bootstrap is enabled"):
|
|
importlib.reload(app_main)
|