Files
unitforge/tests/test_unit_file.py
William Valentin 860f60591c Fix contrast issues with text-muted and bg-dark classes
- Fixed Bootstrap bg-dark class to use better contrasting color
- Added comprehensive text-muted contrast fixes for various contexts
- Improved dark theme colors for better accessibility
- Fixed CSS inheritance issues for code elements in dark contexts
- All color choices meet WCAG AA contrast requirements
2025-09-14 14:58:35 -07:00

299 lines
9.2 KiB
Python

#!/usr/bin/env python3
"""
Tests for the systemd unit file parser and validator.
"""
from backend.app.core.unit_file import SystemdUnitFile, UnitType, create_unit_file
class TestSystemdUnitFile:
"""Test cases for the SystemdUnitFile class."""
def test_parse_simple_service(self):
"""Test parsing a simple service unit file."""
content = """[Unit]
Description=Test Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/test
User=testuser
Restart=on-failure
[Install]
WantedBy=multi-user.target
"""
unit = SystemdUnitFile(content=content)
assert unit.get_unit_type() == UnitType.SERVICE
info = unit.get_info()
assert info.description == "Test Service"
assert info.unit_type == UnitType.SERVICE
def test_validate_valid_service(self):
"""Test validation of a valid service unit file."""
content = """[Unit]
Description=Valid Service
[Service]
Type=simple
ExecStart=/usr/bin/valid-service
[Install]
WantedBy=multi-user.target
"""
unit = SystemdUnitFile(content=content)
errors = unit.validate()
# Should have no errors
error_list = [e for e in errors if e.severity == "error"]
assert len(error_list) == 0
def test_validate_invalid_service_type(self):
"""Test validation catches invalid service type."""
content = """[Unit]
Description=Invalid Service
[Service]
Type=invalid-type
ExecStart=/usr/bin/test
[Install]
WantedBy=multi-user.target
"""
unit = SystemdUnitFile(content=content)
errors = unit.validate()
# Should have an error about invalid service type
error_list = [e for e in errors if e.severity == "error"]
assert len(error_list) > 0
assert any("Invalid service type" in e.message for e in error_list)
def test_validate_missing_exec_start(self):
"""Test validation catches missing ExecStart for simple service."""
content = """[Unit]
Description=Missing ExecStart
[Service]
Type=simple
User=testuser
[Install]
WantedBy=multi-user.target
"""
unit = SystemdUnitFile(content=content)
errors = unit.validate()
# Should have an error about missing ExecStart
error_list = [e for e in errors if e.severity == "error"]
assert len(error_list) > 0
assert any("ExecStart" in e.message for e in error_list)
def test_parse_timer_unit(self):
"""Test parsing a timer unit file."""
content = """[Unit]
Description=Test Timer
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
"""
unit = SystemdUnitFile(content=content)
assert unit.get_unit_type() == UnitType.TIMER
def test_validate_timer_missing_schedule(self):
"""Test validation catches timer without schedule."""
content = """[Unit]
Description=Timer without schedule
[Timer]
Persistent=true
[Install]
WantedBy=timers.target
"""
unit = SystemdUnitFile(content=content)
errors = unit.validate()
# Should have an error about missing timer specification
error_list = [e for e in errors if e.severity == "error"]
assert len(error_list) > 0
assert any("timing specification" in e.message.lower() for e in error_list)
def test_parse_socket_unit(self):
"""Test parsing a socket unit file."""
content = """[Unit]
Description=Test Socket
[Socket]
ListenStream=127.0.0.1:8080
SocketUser=www-data
[Install]
WantedBy=sockets.target
"""
unit = SystemdUnitFile(content=content)
assert unit.get_unit_type() == UnitType.SOCKET
def test_validate_socket_missing_listen(self):
"""Test validation catches socket without listen specification."""
content = """[Unit]
Description=Socket without listen
[Socket]
SocketUser=www-data
[Install]
WantedBy=sockets.target
"""
unit = SystemdUnitFile(content=content)
errors = unit.validate()
# Should have an error about missing listen specification
error_list = [e for e in errors if e.severity == "error"]
assert len(error_list) > 0
assert any("Listen specification" in e.message for e in error_list)
def test_set_and_get_values(self):
"""Test setting and getting values in unit file."""
unit = SystemdUnitFile()
unit.set_value("Unit", "Description", "Test Description")
unit.set_value("Service", "Type", "simple")
unit.set_value("Service", "ExecStart", "/usr/bin/test")
assert unit.get_value("Unit", "Description") == "Test Description"
assert unit.get_value("Service", "Type") == "simple"
assert unit.get_value("Service", "ExecStart") == "/usr/bin/test"
def test_remove_key(self):
"""Test removing keys from unit file."""
unit = SystemdUnitFile()
unit.set_value("Service", "User", "testuser")
assert unit.get_value("Service", "User") == "testuser"
removed = unit.remove_key("Service", "User")
assert removed is True
assert unit.get_value("Service", "User") is None
def test_to_string(self):
"""Test converting unit file back to string format."""
unit = SystemdUnitFile()
unit.set_value("Unit", "Description", "Test Service")
unit.set_value("Service", "Type", "simple")
unit.set_value("Service", "ExecStart", "/usr/bin/test")
unit.set_value("Install", "WantedBy", "multi-user.target")
content = unit.to_string()
assert "[Unit]" in content
assert "Description=Test Service" in content
assert "[Service]" in content
assert "Type=simple" in content
assert "ExecStart=/usr/bin/test" in content
assert "[Install]" in content
assert "WantedBy=multi-user.target" in content
def test_validate_time_span(self):
"""Test time span validation."""
unit = SystemdUnitFile()
# Valid time spans
valid_content = """[Service]
TimeoutStartSec=30s
RestartSec=5min
"""
unit = SystemdUnitFile(content=valid_content)
errors = unit.validate()
time_errors = [e for e in errors if "time span" in e.message.lower()]
assert len(time_errors) == 0
# Invalid time span
invalid_content = """[Service]
TimeoutStartSec=invalid-time
"""
unit = SystemdUnitFile(content=invalid_content)
errors = unit.validate()
time_errors = [e for e in errors if "time span" in e.message.lower()]
assert len(time_errors) > 0
class TestCreateUnitFile:
"""Test cases for the create_unit_file function."""
def test_create_simple_service(self):
"""Test creating a simple service unit file."""
unit = create_unit_file(
UnitType.SERVICE,
description="Test Service",
exec_start="/usr/bin/test",
user="testuser",
restart="on-failure",
)
assert unit.get_unit_type() == UnitType.SERVICE
assert unit.get_value("Unit", "Description") == "Test Service"
assert unit.get_value("Service", "ExecStart") == "/usr/bin/test"
assert unit.get_value("Service", "User") == "testuser"
assert unit.get_value("Service", "Restart") == "on-failure"
def test_create_timer_unit(self):
"""Test creating a timer unit file."""
unit = create_unit_file(
UnitType.TIMER,
description="Test Timer",
on_calendar="daily",
persistent=True,
)
assert unit.get_unit_type() == UnitType.TIMER
assert unit.get_value("Unit", "Description") == "Test Timer"
assert unit.get_value("Timer", "OnCalendar") == "daily"
assert unit.get_value("Timer", "Persistent") == "true"
def test_create_socket_unit(self):
"""Test creating a socket unit file."""
unit = create_unit_file(
UnitType.SOCKET, description="Test Socket", listen_stream="127.0.0.1:8080"
)
assert unit.get_unit_type() == UnitType.SOCKET
assert unit.get_value("Unit", "Description") == "Test Socket"
assert unit.get_value("Socket", "ListenStream") == "127.0.0.1:8080"
def test_create_mount_unit(self):
"""Test creating a mount unit file."""
unit = create_unit_file(
UnitType.MOUNT,
description="Test Mount",
what="/dev/sdb1",
where="/mnt/data",
type="ext4",
)
assert unit.get_unit_type() == UnitType.MOUNT
assert unit.get_value("Unit", "Description") == "Test Mount"
assert unit.get_value("Mount", "What") == "/dev/sdb1"
assert unit.get_value("Mount", "Where") == "/mnt/data"
assert unit.get_value("Mount", "Type") == "ext4"
def test_create_with_dependencies(self):
"""Test creating unit file with dependencies."""
unit = create_unit_file(
UnitType.SERVICE,
description="Service with dependencies",
exec_start="/usr/bin/test",
requires=["database.service"],
wants=["network.service"],
after=["network.target", "database.service"],
)
assert unit.get_value("Unit", "Requires") == "database.service"
assert unit.get_value("Unit", "Wants") == "network.service"
assert unit.get_value("Unit", "After") == "network.target database.service"