blob: 41d59171a0f580d7b5edb4953e98fab9fd30dfd5 [file]
import time
import pytest
from pyhttpd.depends import needs_dependency
from .env import MONITOR_STATUS, MONITOR_TIMEOUT, TransientService, http_responds
pytestmark = needs_dependency(
"systemd --user manager", TransientService.is_available(),
reason="no per-user systemd manager to run a transient service under",
detected="systemd-run --user is not usable here")
class TestSystemdService:
"""httpd as a real systemd service, end to end.
Everything else here checks what mod_systemd sends. These check what
systemd does with it: hold the unit in "activating" until httpd is
ready, track the right process, and show the reported status text.
"""
@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env):
assert env.apache_stop() == 0
yield
assert env.apache_stop() == 0
@pytest.fixture
def service(self, env) -> TransientService:
svc = TransientService(env, port=env.http_port2)
yield svc
svc.stop()
def test_systemd_005_01_type_notify(self, env, service):
"""systemd-run returns once the unit is active, which for a
Type=notify service means READY=1 has been received, which
mod_systemd sends only after the configuration is loaded."""
r = service.start()
assert r.returncode == 0, f"systemd-run failed: {r.stderr}"
assert service.show('ActiveState') == 'active'
assert http_responds(env.http_port2), \
"the unit was active before the server would answer"
def test_systemd_005_02_main_pid(self, env, service):
"""The process systemd tracks is the httpd parent."""
assert service.start().returncode == 0
assert service.wait_active()
main_pid = int(service.show('MainPID'))
assert main_pid > 0
assert main_pid == service.read_pid()
def test_systemd_005_03_status_text(self, env, service):
"""The status line "systemctl status" shows comes from the monitor
hook, and is refreshed while the server runs."""
assert service.start().returncode == 0
assert service.wait_active()
# First the post_config report, then the periodic one.
assert service.show('StatusText') in ('Configuration loaded.',
'Processing requests...')
end = time.time() + MONITOR_TIMEOUT
text = None
while time.time() < end:
text = service.show('StatusText')
if MONITOR_STATUS.match(text):
break
time.sleep(0.5)
assert MONITOR_STATUS.match(text), \
f"status text was never refreshed by the monitor hook: {text!r}"
def test_systemd_005_04_reload(self, env, service):
"""systemctl reload runs httpd -k graceful and the unit stays
active throughout."""
assert service.start().returncode == 0
assert service.wait_active()
pid = int(service.show('MainPID'))
r = service.systemctl('reload', f'{service.unit}.service')
assert r.returncode == 0, f"reload failed: {r.stderr}"
assert service.show('ActiveState') == 'active'
assert int(service.show('MainPID')) == pid
assert http_responds(env.http_port2)
def test_systemd_005_05_stop(self, env, service):
"""The unit stops cleanly, without systemd having to time out and
kill it."""
assert service.start().returncode == 0
assert service.wait_active()
r = service.systemctl('stop', f'{service.unit}.service')
assert r.returncode == 0, f"stop failed: {r.stderr}"
assert service.show('ActiveState') == 'inactive'
assert service.show('Result') == 'success'
assert not http_responds(env.http_port2)