Files
pyMC_Repeater/tests/test_restart_job_submission.py
T

116 lines
4.3 KiB
Python

"""The restart command must run outside the service being restarted."""
import subprocess
from pathlib import Path
from unittest.mock import Mock
import pytest
from repeater import service_utils as su
@pytest.fixture(autouse=True)
def systemd_host(monkeypatch):
monkeypatch.setattr(su, "is_container", lambda: False)
monkeypatch.setattr(su, "is_buildroot", lambda: False)
monkeypatch.setattr(su.os, "geteuid", lambda: 1000)
@pytest.mark.parametrize("root", [False, True])
def test_restart_submits_delayed_external_job(monkeypatch, root):
monkeypatch.setattr(su.os, "geteuid", lambda: 0 if root else 1000)
monkeypatch.setattr(su.os.path, "exists", lambda p: p == su._SUDO_SYSTEMCTL_BIN)
run = Mock(return_value=subprocess.CompletedProcess([], 0, "", ""))
monkeypatch.setattr(su.subprocess, "run", run)
ok, message = su.restart_service()
assert ok and "initiated" in message
run.assert_called_once()
args = run.call_args.args[0]
assert "/usr/bin/systemd-run" in args
assert "--on-active=2s" in args
assert "--timer-property=AccuracySec=100ms" in args
assert "--timer-property=RemainAfterElapse=no" in args
assert "--collect" in args
expected_systemctl = su._SYSTEMCTL_BIN if root else su._SUDO_SYSTEMCTL_BIN
assert args[-3:] == [expected_systemctl, "restart", "openhop-repeater"]
if not root:
assert args[:2] == [su._SUDO_BIN, "--non-interactive"]
else:
assert args[0] == "/usr/bin/systemd-run"
def test_restart_non_root_prefers_sudoers_whitelisted_systemctl_path(monkeypatch):
monkeypatch.setattr(su.os, "geteuid", lambda: 1000)
monkeypatch.setattr(su.os.path, "exists", lambda p: p == su._SUDO_SYSTEMCTL_BIN)
run = Mock(return_value=subprocess.CompletedProcess([], 0, "", ""))
monkeypatch.setattr(su.subprocess, "run", run)
ok, _message = su.restart_service()
assert ok is True
args = run.call_args.args[0]
assert args[-3:] == [su._SUDO_SYSTEMCTL_BIN, "restart", "openhop-repeater"]
@pytest.mark.parametrize("outcome", ["timeout", "interrupted"])
def test_failed_submission_does_not_claim_success_or_retry(monkeypatch, outcome):
run = Mock()
if outcome == "timeout":
run.side_effect = subprocess.TimeoutExpired("systemd-run", 5)
else:
run.return_value = subprocess.CompletedProcess([], -15, "", "Access denied")
monkeypatch.setattr(su.subprocess, "run", run)
ok, message = su.restart_service()
assert not ok
assert "unconfirmed" in message.lower()
run.assert_called_once()
def test_non_root_denied_schedule_retries_legacy_and_succeeds(monkeypatch):
monkeypatch.setattr(su.os, "geteuid", lambda: 1000)
monkeypatch.setattr(su.os.path, "exists", lambda p: p == su._SUDO_SYSTEMCTL_BIN)
run = Mock(
side_effect=[
subprocess.CompletedProcess([], 1, "", "sudo: a password is required"),
subprocess.CompletedProcess([], 0, "", ""),
]
)
monkeypatch.setattr(su.subprocess, "run", run)
ok, message = su.restart_service()
assert ok is True
assert "legacy fallback" in message
assert run.call_count == 2
def test_non_root_denied_schedule_legacy_interrupted_is_likely_success(monkeypatch):
monkeypatch.setattr(su.os, "geteuid", lambda: 1000)
monkeypatch.setattr(su.os.path, "exists", lambda p: p == su._SUDO_SYSTEMCTL_BIN)
run = Mock(
side_effect=[
subprocess.CompletedProcess([], 1, "", "sudo: a password is required"),
subprocess.CompletedProcess([], -15, "", ""),
]
)
monkeypatch.setattr(su.subprocess, "run", run)
ok, message = su.restart_service()
assert ok is True
assert "likely initiated" in message
assert run.call_count == 2
def test_installer_authorizes_only_fixed_restart_timer_command():
script = (Path(__file__).resolve().parents[1] / "manage.sh").read_text()
rules = [line for line in script.splitlines() if "NOPASSWD:" in line]
assert len(rules) == 2
command = (
"/usr/bin/systemd-run --quiet --collect --unit=openhop-repeater-restart "
"--on-active=2s --timer-property=AccuracySec=100ms "
"--timer-property=RemainAfterElapse=no /usr/bin/systemctl restart openhop-repeater"
)
assert all(command in line for line in rules)
assert "*" not in command