Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions backend/tests/test_apm_observability.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

ROOT_DIR = Path(__file__).parent.parent.parent


def test_observability_compose_file_exists():
assert (ROOT_DIR / "docker-compose.infra.yml").exists()

Expand Down Expand Up @@ -89,3 +90,79 @@ def test_telemetry_logs_error_on_missing_hostname(monkeypatch, caplog):
"Invalid OTEL exporter endpoint URL: missing hostname; continuing without tracing."
]
assert telemetry_records[0].exc_info is None


def test_telemetry_setup_success(monkeypatch, caplog):
from unittest.mock import patch
from fastapi import FastAPI
from core import telemetry

app = FastAPI()
monkeypatch.setenv("ENABLE_OTEL", "1")
monkeypatch.setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317")
monkeypatch.setenv("OTEL_EXPORTER_OTLP_INSECURE", "1")
caplog.set_level(logging.INFO, logger=telemetry.logger.name)

with patch("opentelemetry.trace.set_tracer_provider") as mock_set_provider, patch(
"opentelemetry.exporter.otlp.proto.grpc.trace_exporter.OTLPSpanExporter"
) as mock_exporter, patch(
"opentelemetry.sdk.trace.export.BatchSpanProcessor"
) as mock_processor, patch(
"opentelemetry.instrumentation.fastapi.FastAPIInstrumentor"
) as mock_instrumentor, patch(
"opentelemetry.sdk.trace.TracerProvider"
) as mock_provider, patch(
"opentelemetry.sdk.resources.Resource"
):

telemetry.setup_telemetry(app)

assert getattr(app.state, telemetry._TELEMETRY_STATE_KEY) is True
mock_provider.assert_called_once()
mock_set_provider.assert_called_once()
mock_exporter.assert_called_once_with(
endpoint="http://localhost:4317", insecure=True
)
mock_processor.assert_called_once()
mock_instrumentor.instrument_app.assert_called_once_with(app)

assert "OpenTelemetry instrumentation completed successfully." in [
r.message for r in caplog.records
]


def test_telemetry_early_return_if_already_configured(caplog):
from fastapi import FastAPI
from core import telemetry

app = FastAPI()
setattr(app.state, telemetry._TELEMETRY_STATE_KEY, True)
caplog.set_level(logging.DEBUG, logger=telemetry.logger.name)

telemetry.setup_telemetry(app)

assert "OpenTelemetry instrumentation is already configured." in [
r.message for r in caplog.records
]


def test_telemetry_setup_exception_handling(monkeypatch, caplog):
from unittest.mock import patch
from fastapi import FastAPI
from core import telemetry

app = FastAPI()
monkeypatch.setenv("ENABLE_OTEL", "1")
monkeypatch.setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317")
caplog.set_level(logging.ERROR, logger=telemetry.logger.name)

with patch(
"opentelemetry.sdk.trace.TracerProvider",
side_effect=Exception("Mocked failure"),
):
telemetry.setup_telemetry(app)

assert getattr(app.state, telemetry._TELEMETRY_STATE_KEY, False) is False
assert "OpenTelemetry setup failed; continuing without tracing." in [
r.message for r in caplog.records
]
43 changes: 43 additions & 0 deletions backend/tests/test_config_canonical_origin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Focused regression tests for canonical origin rendering."""

from core.config import canonical_origin


def test_canonical_origin_http_default_port():
"""Omit HTTP's default port while normalizing scheme and host casing."""
assert canonical_origin("http", "example.com", 80) == "http://example.com"
assert canonical_origin("HTTP", "example.com", 80) == "http://example.com"
assert canonical_origin("http", "EXAMPLE.COM", 80) == "http://example.com"


def test_canonical_origin_https_default_port():
"""Omit HTTPS's default port."""
assert canonical_origin("https", "example.com", 443) == "https://example.com"


def test_canonical_origin_custom_port():
"""Preserve explicit non-default HTTP and HTTPS ports."""
assert canonical_origin("http", "example.com", 8080) == "http://example.com:8080"
assert canonical_origin("https", "example.com", 8443) == "https://example.com:8443"


def test_canonical_origin_none_port():
"""Render an origin without a port when the caller supplies none."""
assert canonical_origin("http", "example.com", None) == "http://example.com"
assert canonical_origin("https", "example.com", None) == "https://example.com"


def test_canonical_origin_ipv6_host():
"""Bracket IPv6 hosts exactly once and preserve non-default ports."""
assert canonical_origin("http", "2001:db8::1", 80) == "http://[2001:db8::1]"
assert canonical_origin("http", "[2001:db8::1]", 80) == "http://[2001:db8::1]"
assert canonical_origin("https", "2001:db8::1", 443) == "https://[2001:db8::1]"
assert canonical_origin("http", "2001:db8::1", 8080) == "http://[2001:db8::1]:8080"


def test_canonical_origin_other_schemes():
"""Non-HTTP schemes retain explicit ports and omit absent ports."""
assert canonical_origin("ws", "example.com", 80) == "ws://example.com:80"
assert canonical_origin("wss", "example.com", 443) == "wss://example.com:443"
assert canonical_origin("ftp", "example.com", 21) == "ftp://example.com:21"
assert canonical_origin("ws", "example.com", None) == "ws://example.com"
33 changes: 32 additions & 1 deletion backend/tests/test_env_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import pytest

from core.env_paths import expand_operator_path, operator_home
from core.env_paths import (
ENV_FILE_PATHS,
expand_operator_path,
operator_env_file_paths,
operator_home,
)


def test_operator_home_resolves_home_override(monkeypatch, tmp_path: Path) -> None:
Expand Down Expand Up @@ -32,3 +37,29 @@ def test_expand_operator_path_rejects_home_escape(monkeypatch, tmp_path: Path) -

with pytest.raises(ValueError, match="escapes"):
expand_operator_path("~/../outside.env")


def test_operator_env_file_paths_default(monkeypatch, tmp_path: Path) -> None:
home = tmp_path / "home"
home.mkdir()
monkeypatch.setenv("HOME", str(home))

paths = operator_env_file_paths()
expected = tuple(str(expand_operator_path(p)) for p in ENV_FILE_PATHS)
assert paths == expected
assert str(home.resolve() / ".env") in paths


def test_operator_env_file_paths_custom(monkeypatch, tmp_path: Path) -> None:
home = tmp_path / "home"
home.mkdir()
monkeypatch.setenv("HOME", str(home))

custom_paths = ["~/.env.custom", "local.env", "~"]
paths = operator_env_file_paths(custom_paths)
expected = (
str(home.resolve() / ".env.custom"),
"local.env",
str(home.resolve()),
)
assert paths == expected
Loading