from __future__ import annotations from pathlib import Path import pytest from app.observability.config import get_observability_config ENV_VARS = ( "OTEL_ENABLED", "OTEL_MODE", "OTEL_EXPORTER_OTLP_ENDPOINT", "SIGNOZ_UI_URL", "OBSERVABILITY_ARTIFACT_ROOT", "EVALUATION_RUN", "DEPLOYMENT_ENV", ) @pytest.fixture(autouse=True) def clean_observability_env(monkeypatch): """Every test starts from a clean slate regardless of the host shell's env.""" for name in ENV_VARS: monkeypatch.delenv(name, raising=False) yield def test_defaults_when_env_unset(): config = get_observability_config() assert config.enabled is False assert config.mode == "disabled" assert config.otlp_endpoint == "http://127.0.0.1:4318" assert config.signoz_ui_url == "http://127.0.0.1:8080" assert config.artifact_root == Path("~/.studybuddy/observability").expanduser() def test_reads_all_env_vars(monkeypatch, tmp_path): monkeypatch.setenv("OTEL_ENABLED", "true") monkeypatch.setenv("OTEL_MODE", "local") monkeypatch.setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector.internal:4318") monkeypatch.setenv("SIGNOZ_UI_URL", "http://signoz.internal:8080") monkeypatch.setenv("OBSERVABILITY_ARTIFACT_ROOT", str(tmp_path)) config = get_observability_config() assert config.enabled is True assert config.mode == "local" assert config.otlp_endpoint == "http://collector.internal:4318" assert config.signoz_ui_url == "http://signoz.internal:8080" assert config.artifact_root == tmp_path def test_demo_deployment_forces_observability_off(monkeypatch): monkeypatch.setenv("DEPLOYMENT_ENV", "demo") monkeypatch.setenv("OTEL_ENABLED", "true") monkeypatch.setenv("OTEL_MODE", "full") config = get_observability_config() assert config.enabled is False assert config.mode == "disabled" def test_artifact_root_expands_user_home(monkeypatch): monkeypatch.setenv("OBSERVABILITY_ARTIFACT_ROOT", "~/.studybuddy/observability") config = get_observability_config() assert "~" not in str(config.artifact_root) assert config.artifact_root == Path("~/.studybuddy/observability").expanduser() @pytest.mark.parametrize("raw,expected", [("true", True), ("1", True), ("yes", True), ("on", True), ("True", True)]) def test_otel_enabled_truthy_strings(monkeypatch, raw, expected): monkeypatch.setenv("OTEL_ENABLED", raw) assert get_observability_config().enabled is expected @pytest.mark.parametrize("raw,expected", [("false", False), ("0", False), ("no", False), ("off", False), ("", False)]) def test_otel_enabled_falsy_strings(monkeypatch, raw, expected): monkeypatch.setenv("OTEL_ENABLED", raw) assert get_observability_config().enabled is expected def test_invalid_mode_falls_back_to_disabled_in_ordinary_startup(monkeypatch): monkeypatch.setenv("OTEL_MODE", "bogus-mode") config = get_observability_config() assert config.mode == "disabled" def test_invalid_mode_raises_descriptive_error_in_evaluation_run(monkeypatch): monkeypatch.setenv("OTEL_MODE", "bogus-mode") monkeypatch.setenv("EVALUATION_RUN", "true") with pytest.raises(ValueError, match="bogus-mode"): get_observability_config() def test_missing_mode_defaults_to_disabled_in_evaluation_run(monkeypatch): # No OTEL_MODE set at all -> defaults to "disabled". A benchmark run # explicitly opting out of telemetry is a valid choice, not a # misconfiguration, so this must not raise. monkeypatch.setenv("EVALUATION_RUN", "true") config = get_observability_config() assert config.mode == "disabled" def test_explicit_disabled_mode_does_not_raise_in_evaluation_run(monkeypatch): monkeypatch.setenv("OTEL_MODE", "disabled") monkeypatch.setenv("EVALUATION_RUN", "true") config = get_observability_config() assert config.mode == "disabled" def test_bogus_mode_still_raises_in_evaluation_run(monkeypatch): monkeypatch.setenv("OTEL_MODE", "bogus-garbage") monkeypatch.setenv("EVALUATION_RUN", "true") with pytest.raises(ValueError, match="bogus-garbage"): get_observability_config() def test_valid_mode_with_evaluation_run_succeeds(monkeypatch): monkeypatch.setenv("OTEL_MODE", "full") monkeypatch.setenv("EVALUATION_RUN", "true") config = get_observability_config() assert config.mode == "full" def test_local_mode_with_evaluation_run_succeeds(monkeypatch): monkeypatch.setenv("OTEL_MODE", "local") monkeypatch.setenv("EVALUATION_RUN", "true") config = get_observability_config() assert config.mode == "local"