1
0
mirror of https://github.com/apache/httpd.git synced 2026-10-23 22:49:01 +03:00
Files

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.