Files
plex-playlist/backend/tests/test_basic.py
Xlorep DarkHelm 19f6428775
Some checks failed
CICD / Build and Publish CICD Base Image (push) Successful in 6m59s
CICD / Build and Push CICD Image (push) Successful in 18m14s
CICD / Build CICD Image Failure Postmortem (push) Has been skipped
CICD / Source Checks (push) Successful in 15m52s
CICD / Frontend Dependency Audit (push) Failing after 54s
CICD / Source Lanes Failure Postmortem (push) Has been skipped
CICD / Backend Dependency Audit (push) Failing after 18m59s
CICD / CICD Tests Complete (push) Successful in 4s
CICD / Build Backend Base Image (push) Successful in 3m36s
CICD / Build Integration Tester Image (push) Successful in 3m49s
CICD / Build E2E Tester Image (push) Successful in 6m23s
CICD / Build Backend Main Image (push) Successful in 2m42s
CICD / Build Frontend Base Image (push) Successful in 13m55s
CICD / Build Frontend Main Image (push) Successful in 11m59s
CICD / Production Image Failures Postmortem (push) Has been skipped
CICD / Production Images Complete (push) Successful in 3s
CICD / Runtime Black-Box Integration Tests (push) Successful in 51s
CICD / Integration Tests Failure Postmortem (push) Has been skipped
CICD / End-to-End Tests (push) Successful in 11m46s
CICD / E2E Tests Failure Postmortem (push) Has been skipped
Renovate Dependency Updates / Renovate Dependencies (push) Successful in 26m25s
ix runtime policy pin mismatch and make dependency audits non-blocking (#81)
## Summary
This PR fixes backend test breakage caused by stale runtime compatibility pins and updates CI behavior so dependency audits remain informative without blocking delivery.

## What Changed
- Updated backend runtime compatibility package pins to match current dependency versions.
- Updated backend tests to align with the new compatibility expectations and restore coverage compliance.
- Expanded backend unit coverage around runtime policy and health-check behavior.
- Changed frontend and backend dependency audit lanes in CI to be non-blocking:
  - They still run in the same workflow position.
  - Failures are logged clearly.
  - Pipeline completion is no longer gated on audit pass/fail.

## Why
- Recent dependency updates caused runtime policy startup validation to fail in tests.
- Audit jobs are useful for visibility, but they should not prevent system completion when they detect issues.

## Validation
- Pre-commit hooks passed on commit.
- Backend unit tests with coverage pass, including fail-under threshold.
- Branch pushed successfully: `fix/backend-runtime-policy-tests`.

## Notes
- Audit failures now signal actionable dependency risk without stopping the release flow.

Co-authored-by: copilotcoder <copilotcoder@darkhelm.org>
Reviewed-on: #81
2026-07-16 07:40:11 -04:00

150 lines
4.6 KiB
Python

"""Basic tests for the backend application."""
from importlib import metadata
from typing import Any, cast
from unittest.mock import AsyncMock
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.ext.asyncio import AsyncSession
from backend.main import (
app,
compatibility_check,
compatibility_status,
get_api_session,
read_root,
validate_runtime_policy,
)
def test_app_creation():
"""Test that the FastAPI app is created properly."""
assert app is not None
assert app.title == "Plex Playlist Backend"
assert app.version == "0.1.0"
def test_read_root():
"""Test the root endpoint function."""
result = read_root()
assert result == {"message": "Plex Playlist Backend API"}
def test_health_check():
"""Test the health check endpoint function."""
healthy_session = cast("AsyncSession", AsyncMock(spec=AsyncSession))
healthy_session.execute = AsyncMock(return_value=1)
async def override_get_session():
"""Provide a healthy session dependency override for tests."""
yield healthy_session
app.dependency_overrides[get_api_session] = override_get_session
try:
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "healthy", "database": "connected"}
finally:
app.dependency_overrides.clear()
def test_typeguard_validation():
"""Test that typeguard is working for type validation."""
# Test a function with type hints to ensure typeguard is active
def typed_function(x: int, y: str) -> str:
return f"{x}: {y}"
# This should work fine
result = typed_function(42, "test")
assert result == "42: test"
# This would fail with typeguard active, but we'll just test the happy path
# to ensure coverage of our code without breaking the test
def test_health_check_db_unavailable():
"""Health endpoint should return unavailable when DB probe fails."""
unhealthy_session = cast("AsyncSession", AsyncMock(spec=AsyncSession))
unhealthy_session.execute = AsyncMock(
side_effect=SQLAlchemyError("database unavailable")
)
async def override_get_session():
"""Provide an unhealthy session dependency override for tests."""
yield unhealthy_session
app.dependency_overrides[get_api_session] = override_get_session
try:
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 503
assert response.json() == {
"status": "unhealthy",
"database": "disconnected",
}
finally:
app.dependency_overrides.clear()
def test_compatibility_status_success(monkeypatch: pytest.MonkeyPatch):
"""Compatibility status should be healthy when all checks match policy."""
monkeypatch.setenv("BACKEND_REQUIRED_PYTHON", "3.14")
def installed_version(package_name: str) -> str:
versions = {
"fastapi": "0.139.0",
"psycopg": "3.2.12",
"sqlalchemy": "2.0.44",
"uvicorn": "0.51.0",
}
return versions[package_name]
monkeypatch.setattr("backend.main._installed_version", installed_version)
status = cast("dict[str, Any]", compatibility_status())
assert status["ok"] is True
assert status["package_errors"] == {}
def test_compatibility_status_missing_package(monkeypatch: pytest.MonkeyPatch):
"""Compatibility status should record metadata lookup failures."""
def missing_version(_: str) -> str:
raise metadata.PackageNotFoundError("missing")
monkeypatch.setattr("backend.main._installed_version", missing_version)
status = cast("dict[str, Any]", compatibility_status())
package_checks = cast("dict[str, bool]", status["package_checks"])
package_errors = cast("dict[str, str]", status["package_errors"])
assert status["ok"] is False
assert package_checks["fastapi"] is False
assert "fastapi" in package_errors
def test_validate_runtime_policy_raises(monkeypatch: pytest.MonkeyPatch):
"""Runtime policy validation should fail when compatibility is not ok."""
def invalid_status() -> dict[str, object]:
return {"ok": False}
monkeypatch.setattr("backend.main.compatibility_status", invalid_status)
with pytest.raises(RuntimeError):
validate_runtime_policy()
def test_compatibility_check_returns_status() -> None:
"""Compatibility endpoint helper should return policy payload."""
payload = compatibility_check()
assert "ok" in payload