"""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 == ""