| 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. |