Files
gh-christianlouis-docuelevate/tests/test_release_names.py
2026-03-01 18:38:07 +00:00

262 lines
10 KiB
Python

"""Tests for release naming functionality in app/config.py and app/views/status.py."""
import json
import os
from unittest.mock import Mock, patch
import pytest
@pytest.mark.unit
class TestReleaseNameProperty:
"""Tests for the Settings.release_name property."""
def test_release_name_returns_codename_for_minor_prefix(self, tmp_path):
"""Test release_name returns codename matching minor version prefix."""
release_data = {
"releases": {
"0.5": {"codename": "Foundation", "description": "Core platform"},
}
}
release_file = tmp_path / "release_names.json"
release_file.write_text(json.dumps(release_data))
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.5.3")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result == "Foundation"
def test_release_name_returns_codename_for_exact_match(self, tmp_path):
"""Test release_name returns codename for exact version match."""
release_data = {
"releases": {
"1.0.0": {"codename": "Summit"},
}
}
release_file = tmp_path / "release_names.json"
release_file.write_text(json.dumps(release_data))
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "1.0.0")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result == "Summit"
def test_release_name_returns_none_when_no_match(self, tmp_path):
"""Test release_name returns None when version has no codename."""
release_data = {
"releases": {
"0.5": {"codename": "Foundation"},
}
}
release_file = tmp_path / "release_names.json"
release_file.write_text(json.dumps(release_data))
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.9.1")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result is None
def test_release_name_returns_none_when_file_missing(self):
"""Test release_name returns None when release_names.json doesn't exist."""
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.5.0")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value="/nonexistent/release_names.json"),
patch("app.config.os.path.exists", return_value=False),
):
result = s.release_name
assert result is None
def test_release_name_returns_none_for_unknown_version(self):
"""Test release_name returns None when version is 'unknown'."""
from app.config import Settings
s = Settings.__new__(Settings)
with patch.object(type(s), "version", new_callable=lambda: property(lambda self: "unknown")):
result = s.release_name
assert result is None
def test_release_name_returns_none_for_empty_version(self):
"""Test release_name returns None when version is empty."""
from app.config import Settings
s = Settings.__new__(Settings)
with patch.object(type(s), "version", new_callable=lambda: property(lambda self: "")):
result = s.release_name
assert result is None
def test_release_name_handles_invalid_json(self, tmp_path):
"""Test release_name handles corrupt JSON gracefully."""
release_file = tmp_path / "release_names.json"
release_file.write_text("{invalid json")
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.5.0")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result is None
def test_release_name_handles_missing_releases_key(self, tmp_path):
"""Test release_name handles JSON without 'releases' key."""
release_file = tmp_path / "release_names.json"
release_file.write_text(json.dumps({"something_else": {}}))
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.5.0")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result is None
def test_release_name_prefers_exact_over_minor(self, tmp_path):
"""Test release_name prefers exact version match over minor prefix."""
release_data = {
"releases": {
"0.5.0": {"codename": "ExactMatch"},
"0.5": {"codename": "MinorMatch"},
}
}
release_file = tmp_path / "release_names.json"
release_file.write_text(json.dumps(release_data))
from app.config import Settings
s = Settings.__new__(Settings)
with (
patch.object(type(s), "version", new_callable=lambda: property(lambda self: "0.5.0")),
patch("app.config.os.path.dirname"),
patch("app.config.os.path.join", return_value=str(release_file)),
patch("app.config.os.path.exists", return_value=True),
):
result = s.release_name
assert result == "ExactMatch"
@pytest.mark.unit
class TestReleaseNameInStatusView:
"""Tests for release name display in status dashboard."""
@patch("app.views.status.get_provider_status")
@patch("app.views.status.templates")
@patch("app.views.status.settings")
@patch("app.views.status.os.path.exists")
@pytest.mark.asyncio
async def test_status_dashboard_includes_release_name(
self, mock_exists, mock_settings, mock_templates, mock_providers
):
"""Test status dashboard passes release_name to template context."""
from app.views.status import status_dashboard
mock_exists.return_value = False
mock_providers.return_value = {}
mock_settings.version = "0.5.3"
mock_settings.build_date = "2024-01-01"
mock_settings.debug = False
mock_settings.git_sha = "abc123"
mock_settings.notification_urls = []
mock_settings.release_name = "Foundation"
mock_request = Mock()
await status_dashboard(mock_request)
call_args = mock_templates.TemplateResponse.call_args
context = call_args[0][1]
assert context["release_name"] == "Foundation"
@patch("app.views.status.get_provider_status")
@patch("app.views.status.templates")
@patch("app.views.status.settings")
@patch("app.views.status.os.path.exists")
@pytest.mark.asyncio
async def test_status_dashboard_handles_missing_release_name(
self, mock_exists, mock_settings, mock_templates, mock_providers
):
"""Test status dashboard handles missing release_name attribute gracefully."""
from app.views.status import status_dashboard
mock_exists.return_value = False
mock_providers.return_value = {}
mock_settings.version = "0.9.0"
mock_settings.build_date = "2024-01-01"
mock_settings.debug = False
mock_settings.git_sha = "abc123"
mock_settings.notification_urls = []
# Simulate settings without release_name attribute
del mock_settings.release_name
mock_request = Mock()
await status_dashboard(mock_request)
call_args = mock_templates.TemplateResponse.call_args
context = call_args[0][1]
assert context["release_name"] is None
@pytest.mark.unit
class TestReleaseNamesJson:
"""Tests for the release_names.json data file."""
def test_release_names_json_is_valid(self):
"""Test that release_names.json is valid JSON."""
release_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "release_names.json")
with open(release_file, "r") as f:
data = json.load(f)
assert "releases" in data
assert isinstance(data["releases"], dict)
def test_release_names_json_entries_have_codename(self):
"""Test that all entries in release_names.json have a codename."""
release_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "release_names.json")
with open(release_file, "r") as f:
data = json.load(f)
for version, entry in data["releases"].items():
assert "codename" in entry, f"Missing codename for version {version}"
assert isinstance(entry["codename"], str), f"Codename for {version} must be a string"
assert len(entry["codename"]) > 0, f"Codename for {version} must not be empty"
def test_release_names_json_codenames_are_unique(self):
"""Test that all codenames in release_names.json are unique."""
release_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "release_names.json")
with open(release_file, "r") as f:
data = json.load(f)
codenames = [entry["codename"] for entry in data["releases"].values()]
assert len(codenames) == len(set(codenames)), "Codenames must be unique"