Files
core-api/tests/test_service_groups.py
jpmschweitzerandClaude Opus 4.5 ac92607003 Remove Uptime Kuma integration
- Delete kuma_client.py and all Kuma-related code
- Remove /infrastructure/monitors endpoints
- Update service start/stop to use Portainer only
- Simplify service control widget to show container status
- Remove Kuma config and credentials
- Delete stale memory tests (moved to core-ai service)
- Add test infrastructure with pytest
- Add tests for service_groups, config, and health endpoints
- Bump version to 1.1.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 12:04:05 +01:00

147 lines
5.1 KiB
Python

"""Tests for service_groups module."""
import pytest
from src.service_groups import (
ALWAYS_ON_SERVICES,
SERVICE_GROUPS,
is_always_on,
get_service_group,
get_group_name,
list_service_groups,
list_stoppable_services,
validate_stop_request,
)
class TestAlwaysOnServices:
"""Test always-on service configuration."""
def test_always_on_services_includes_infrastructure(self):
"""Critical infrastructure services should be in always-on list."""
assert "portainer" in ALWAYS_ON_SERVICES
assert "nginx-proxy-manager" in ALWAYS_ON_SERVICES
assert "core-api" in ALWAYS_ON_SERVICES
def test_uptime_kuma_not_in_always_on(self):
"""Uptime Kuma was removed from always-on list."""
assert "uptime-kuma" not in ALWAYS_ON_SERVICES
class TestIsAlwaysOn:
"""Test is_always_on function."""
def test_is_always_on_returns_true_for_infrastructure(self):
"""Infrastructure services should return True."""
assert is_always_on("portainer") is True
assert is_always_on("nginx-proxy-manager") is True
assert is_always_on("core-api") is True
def test_is_always_on_case_insensitive(self):
"""Function should be case-insensitive."""
assert is_always_on("PORTAINER") is True
assert is_always_on("Portainer") is True
assert is_always_on("PoRtAiNeR") is True
def test_is_always_on_returns_false_for_stoppable(self):
"""Stoppable services should return False."""
assert is_always_on("jellyfin") is False
assert is_always_on("nextcloud") is False
assert is_always_on("unknown-service") is False
class TestGetServiceGroup:
"""Test get_service_group function."""
def test_returns_group_members_for_grouped_service(self):
"""Should return all services in the group."""
# Assuming jellyfin is defined in SERVICE_GROUPS
if "jellyfin" in SERVICE_GROUPS:
result = get_service_group("jellyfin")
assert "jellyfin" in result
def test_returns_single_item_for_ungrouped_service(self):
"""Ungrouped services should return themselves."""
result = get_service_group("some-random-service")
assert result == ["some-random-service"]
def test_returns_copy_not_reference(self):
"""Should return a copy to prevent modification."""
if SERVICE_GROUPS:
group_name = list(SERVICE_GROUPS.keys())[0]
result1 = get_service_group(group_name)
result2 = get_service_group(group_name)
assert result1 is not result2
class TestGetGroupName:
"""Test get_group_name function."""
def test_returns_group_name_for_grouped_service(self):
"""Should return group name for services in groups."""
# If ai-stack group exists with ollama
if "ai-stack" in SERVICE_GROUPS and "ollama" in SERVICE_GROUPS["ai-stack"]:
assert get_group_name("ollama") == "ai-stack"
def test_returns_service_name_for_ungrouped(self):
"""Ungrouped services should return their own name."""
assert get_group_name("random-service") == "random-service"
class TestListServiceGroups:
"""Test list_service_groups function."""
def test_returns_all_groups(self):
"""Should return all defined service groups."""
result = list_service_groups()
assert isinstance(result, dict)
assert result == SERVICE_GROUPS
def test_returns_copy(self):
"""Should return a copy to prevent modification."""
result = list_service_groups()
assert result is not SERVICE_GROUPS
class TestListStoppableServices:
"""Test list_stoppable_services function."""
def test_returns_list(self):
"""Should return a list."""
result = list_stoppable_services()
assert isinstance(result, list)
def test_excludes_always_on_services(self):
"""Should not include always-on services."""
result = list_stoppable_services()
for service in result:
assert not is_always_on(service), f"{service} is always-on but in stoppable list"
class TestValidateStopRequest:
"""Test validate_stop_request function."""
def test_valid_for_stoppable_services(self):
"""Should return valid for stoppable services."""
stoppable = list_stoppable_services()
if stoppable:
is_valid, error = validate_stop_request([stoppable[0]])
assert is_valid is True
assert error == ""
def test_invalid_for_always_on_services(self):
"""Should return invalid for always-on services."""
is_valid, error = validate_stop_request(["portainer"])
assert is_valid is False
assert "always-on" in error.lower()
assert "portainer" in error
def test_invalid_if_any_service_is_always_on(self):
"""Should fail if any service in list is always-on."""
is_valid, error = validate_stop_request(["jellyfin", "portainer"])
assert is_valid is False
def test_valid_for_empty_list(self):
"""Empty list should be valid."""
is_valid, error = validate_stop_request([])
assert is_valid is True
assert error == ""