Restore backend coverage for runtime pin helpers
All checks were successful
CICD / Build and Push CICD Images (push) Successful in 41m21s
CICD / Build CICD Image Failure Postmortem (push) Has been skipped
CICD / Source Checks (push) Successful in 7m13s
CICD / Source Lanes Failure Postmortem (push) Has been skipped
CICD / Dependency Audits (Informational) (push) Successful in 7m37s
CICD / CICD Tests Complete (push) Successful in 10s
CICD / Build Tester Images (push) Successful in 3m45s
CICD / Build Release Images (push) Successful in 31m50s
CICD / Production Image Failures Postmortem (push) Has been skipped
CICD / Production Images Complete (push) Successful in 2s
CICD / Runtime Black-Box Integration Tests (push) Successful in 53s
CICD / Integration Tests Failure Postmortem (push) Has been skipped
CICD / End-to-End Tests (push) Successful in 3m17s
CICD / E2E Tests Failure Postmortem (push) Has been skipped
CICD / Promote Staging Images To Release (push) Successful in 2m4s
All checks were successful
CICD / Build and Push CICD Images (push) Successful in 41m21s
CICD / Build CICD Image Failure Postmortem (push) Has been skipped
CICD / Source Checks (push) Successful in 7m13s
CICD / Source Lanes Failure Postmortem (push) Has been skipped
CICD / Dependency Audits (Informational) (push) Successful in 7m37s
CICD / CICD Tests Complete (push) Successful in 10s
CICD / Build Tester Images (push) Successful in 3m45s
CICD / Build Release Images (push) Successful in 31m50s
CICD / Production Image Failures Postmortem (push) Has been skipped
CICD / Production Images Complete (push) Successful in 2s
CICD / Runtime Black-Box Integration Tests (push) Successful in 53s
CICD / Integration Tests Failure Postmortem (push) Has been skipped
CICD / End-to-End Tests (push) Successful in 3m17s
CICD / E2E Tests Failure Postmortem (push) Has been skipped
CICD / Promote Staging Images To Release (push) Successful in 2m4s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Basic tests for the backend application."""
|
||||
|
||||
from importlib import metadata
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
@@ -9,6 +10,7 @@ from fastapi.testclient import TestClient
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from backend import main as backend_main
|
||||
from backend.main import (
|
||||
app,
|
||||
compatibility_check,
|
||||
@@ -18,6 +20,12 @@ from backend.main import (
|
||||
validate_runtime_policy,
|
||||
)
|
||||
|
||||
parse_exact_pin = backend_main.__dict__["_parse_exact_pin"]
|
||||
required_package_pins = backend_main.__dict__["_required_package_pins"]
|
||||
required_package_pins_from_dependencies = backend_main.__dict__[
|
||||
"_required_package_pins_from_dependencies"
|
||||
]
|
||||
|
||||
|
||||
def test_app_creation():
|
||||
"""Test that the FastAPI app is created properly."""
|
||||
@@ -142,3 +150,131 @@ def test_compatibility_check_returns_status() -> None:
|
||||
"""Compatibility endpoint helper should return policy payload."""
|
||||
payload = compatibility_check()
|
||||
assert "ok" in payload
|
||||
|
||||
|
||||
def test_parse_exact_pin_handles_valid_and_invalid_requirements() -> None:
|
||||
"""Exact pin parsing should normalize extras and reject malformed pins."""
|
||||
assert parse_exact_pin("psycopg[binary]==3.2.12 ; python_version >= '3.14'") == (
|
||||
"psycopg",
|
||||
"3.2.12",
|
||||
)
|
||||
assert parse_exact_pin("uvicorn>=0.51.0") is None
|
||||
assert parse_exact_pin("==0.51.0") is None
|
||||
assert parse_exact_pin("uvicorn==") is None
|
||||
|
||||
|
||||
def test_required_package_pins_from_dependencies_filters_non_exact_pins() -> None:
|
||||
"""Only exact dependency pins should be included in runtime policy."""
|
||||
dependencies = [
|
||||
"fastapi==0.139.0",
|
||||
"uvicorn>=0.51.0",
|
||||
"psycopg[binary]==3.2.12",
|
||||
]
|
||||
|
||||
assert required_package_pins_from_dependencies(dependencies) == {
|
||||
"fastapi": "0.139.0",
|
||||
"psycopg": "3.2.12",
|
||||
}
|
||||
|
||||
|
||||
def test_required_package_pins_uses_installed_metadata(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Installed project metadata should be the primary pin source."""
|
||||
|
||||
def fake_requires(_: str) -> list[str]:
|
||||
return ["fastapi==0.139.0", "psycopg[binary]==3.2.12"]
|
||||
|
||||
def unexpected_read_text(_: Path, encoding: str = "utf-8") -> str:
|
||||
del encoding
|
||||
raise AssertionError("pyproject fallback should not run")
|
||||
|
||||
monkeypatch.setattr(backend_main.metadata, "requires", fake_requires)
|
||||
monkeypatch.setattr(Path, "read_text", unexpected_read_text)
|
||||
|
||||
assert required_package_pins() == {
|
||||
"fastapi": "0.139.0",
|
||||
"psycopg": "3.2.12",
|
||||
}
|
||||
|
||||
|
||||
def test_required_package_pins_falls_back_to_pyproject(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Pyproject should be used when installed metadata is unavailable or unusable."""
|
||||
|
||||
def missing_requires(_: str) -> list[str]:
|
||||
raise metadata.PackageNotFoundError("missing")
|
||||
|
||||
def fake_read_text(_: Path, encoding: str = "utf-8") -> str:
|
||||
del encoding
|
||||
return "[project]\ndependencies = []\n"
|
||||
|
||||
def fake_toml_loads(_: str) -> dict[str, object]:
|
||||
return {
|
||||
"project": {
|
||||
"dependencies": [
|
||||
"fastapi==0.139.0",
|
||||
123,
|
||||
"psycopg[binary]==3.2.12",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
monkeypatch.setattr(backend_main.metadata, "requires", missing_requires)
|
||||
monkeypatch.setattr(Path, "read_text", fake_read_text)
|
||||
monkeypatch.setattr(backend_main.tomllib, "loads", fake_toml_loads)
|
||||
|
||||
assert required_package_pins() == {
|
||||
"fastapi": "0.139.0",
|
||||
"psycopg": "3.2.12",
|
||||
}
|
||||
|
||||
|
||||
def test_required_package_pins_handles_invalid_pyproject_shapes(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Invalid pyproject structures should safely produce no required pins."""
|
||||
|
||||
def missing_requires(_: str) -> list[str]:
|
||||
raise metadata.PackageNotFoundError("missing")
|
||||
|
||||
def fake_read_text(_: Path, encoding: str = "utf-8") -> str:
|
||||
del encoding
|
||||
return "[project]\ndependencies = []\n"
|
||||
|
||||
def invalid_project_loads(_: str) -> dict[str, object]:
|
||||
return {"project": []}
|
||||
|
||||
def missing_dependencies_loads(_: str) -> dict[str, object]:
|
||||
return {"project": {}}
|
||||
|
||||
monkeypatch.setattr(backend_main.metadata, "requires", missing_requires)
|
||||
monkeypatch.setattr(Path, "read_text", fake_read_text)
|
||||
|
||||
monkeypatch.setattr(backend_main.tomllib, "loads", invalid_project_loads)
|
||||
assert required_package_pins() == {}
|
||||
|
||||
monkeypatch.setattr(backend_main.tomllib, "loads", missing_dependencies_loads)
|
||||
assert required_package_pins() == {}
|
||||
|
||||
|
||||
def test_compatibility_status_rejects_malformed_required_python(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Malformed Python policy strings should fail compatibility checks."""
|
||||
|
||||
def empty_required_package_pins() -> dict[str, str]:
|
||||
return {}
|
||||
|
||||
monkeypatch.setenv("BACKEND_REQUIRED_PYTHON", "3.14.1")
|
||||
monkeypatch.setattr(
|
||||
backend_main,
|
||||
"_required_package_pins",
|
||||
empty_required_package_pins,
|
||||
)
|
||||
|
||||
status = cast("dict[str, Any]", compatibility_status())
|
||||
|
||||
assert status["ok"] is False
|
||||
assert status["python_policy_valid"] is False
|
||||
|
||||
Reference in New Issue
Block a user