mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-10-30 19:51:59 +01:00
116 lines
4.3 KiB
Python
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
|