- 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
299 lines
9.2 KiB
Python
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"
|