blob: 4bdd7af91d145981549092d43ce7e445aa56d801 [file]
mod_systemd tests
=================
What is different about this module
-----------------------------------
mod_systemd has no directives. Everything it does is driven by the
environment httpd was started with, and almost everything it produces goes
to the service manager rather than to a client:
- sd_notify(3) datagrams sent to $NOTIFY_SOCKET at four points: reading
the configuration (pre_config), configuration loaded (post_config),
the MPM starting (pre_mpm, the only notification carrying MAINPID),
and a status line refreshed by the monitor hook.
- listening sockets inherited from the service manager, found through
$LISTEN_FDS. mod_systemd registers the two optional functions
server/listen.c calls, so loading the module is what enables socket
activation and not loading it is what disables it.
- ap_extended_status forced on in pre_config, so that the monitor hook
has request counts to report.
- the watchdog keep-alive, WATCHDOG=1, sent while the service manager
asks for one. Which it does through the environment as well:
WatchdogSec= in the unit becomes $WATCHDOG_USEC, and $WATCHDOG_PID
names the process expected to report.
None of that is observable over HTTP, so the tests observe it directly.
How the tests run without systemd, and without privileges
---------------------------------------------------------
There is no need for a service manager to exercise the protocol. Only
test_005, the last test of test_006, and test_007 involve systemd at all;
the rest run anywhere, and need nothing from the systemd package beyond the
libsystemd httpd itself is linked against.
test_001_notify.py $NOTIFY_SOCKET is an ordinary AF_UNIX datagram
socket the test binds itself (env.NotifyListener).
sd_notify writes to whatever that variable names, so
the test reads httpd's notifications straight off the
socket. HttpdTestEnv.set_httpd_env() puts the
variable into the environment apachectl passes on.
test_002_monitor.py The periodic status line. ap_run_monitor() is
called once every ten turns of the parent's ~1s
loop, so these tests wait up to 25 seconds.
test_003_extended_status.py
The ExtendedStatus side effect, observed through
mod_status.
test_004_socket_activation.py
The test opens the listening socket itself and
hands it to httpd as descriptor 3 with LISTEN_FDS
and LISTEN_PID set, which is the whole protocol.
systemd-socket-activate would do the same, but its
--now option is newer than the systemd on some
distributions, and doing it directly needs no
systemd tooling at all.
test_006_watchdog.py The keep-alive. Mostly the same stand-in socket,
with $WATCHDOG_USEC set in the environment httpd is
started with; env.ForegroundServer runs httpd in the
foreground where $WATCHDOG_PID can name it, which
apachectl cannot do for a parent it has not forked
yet. The last test uses a real unit with
WatchdogSec=, where systemd's own
WatchdogTimestampMonotonic is the evidence that the
pings arrived.
The keep-alive is sent from the monitor hook, so it
is only as frequent as that hook is: about every ten
seconds. A WatchdogSec shorter than twice that
cannot be met, and mod_systemd says so (AH10621)
rather than letting a healthy server be killed.
test_005_service.py The real thing: a transient Type=notify unit run
with "systemd-run --user". This is what checks that
systemd holds the unit in "activating" until READY=1
arrives, tracks the right MainPID, and shows the
reported STATUS= as the unit's status text.
Skipped when the user has no systemd manager.
test_007_notify_reload.py
The reload protocol, as a transient
Type=notify-reload unit: that "systemctl reload"
waits for the new configuration to be in use, that a
configuration which does not parse fails the reload
without disturbing the running server, and that a
reload restarts it gracefully and only once. Also
skipped where systemd is older than 253, which is
where Type=notify-reload arrived.
The whole package is skipped unless mod_systemd was built, which needs
configure --enable-systemd. A static module is enough for everything
except the test which has to leave mod_systemd out of the configuration;
that one needs --enable-systemd=shared.
Running the systemd suites where there is no user session
---------------------------------------------------------
"systemctl --user" needs a per-user manager, which a login session has but
a CI container does not; enabling lingering needs privileges. Where that
is a problem, run the tests inside a container with systemd as pid 1,
which rootless podman supports on a cgroup v2 host:
podman run --rm -it --systemd=always \
-v $PWD:/src:z -w /src registry.fedoraproject.org/fedora:latest \
/usr/sbin/init
then, in another terminal, "podman exec" into it and run pytest as a
non-root user with XDG_RUNTIME_DIR set. The other four suites need none of
this and run anywhere.