]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
oomd: Add regression tests to check Killed notification gives a reason 40689/head
authorChris Down <chris@chrisdown.name>
Sun, 15 Feb 2026 16:25:31 +0000 (00:25 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 17 Feb 2026 05:50:21 +0000 (14:50 +0900)
src/oom/test-oomd-util.c

index 0dada0de6c8d1034cf27eae656844e25c617813a..7332f532a8aaa0dd4baace7c5eee46d2b7aac505 100644 (file)
@@ -1,20 +1,25 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <stdlib.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
+#include "sd-bus.h"
+
 #include "alloc-util.h"
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "oomd-manager.h"
 #include "oomd-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pidref.h"
 #include "process-util.h"
 #include "set.h"
+#include "string-util.h"
 #include "tests.h"
 #include "time-util.h"
 #include "tmpfile-util.h"
@@ -59,6 +64,103 @@ static int fork_and_sleep(unsigned sleep_min, PidRef *ret) {
         return r;
 }
 
+static int setup_local_oomd_bus(sd_bus **ret_server, sd_bus **ret_client) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *server = NULL, *client = NULL;
+        _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
+        int r;
+
+        assert(ret_server);
+        assert(ret_client);
+
+        r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pair);
+        if (r < 0)
+                return -errno;
+
+        r = sd_bus_new(&server);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_set_fd(server, pair[0], pair[0]);
+        if (r < 0)
+                return r;
+        pair[0] = -EBADF;
+
+        r = sd_bus_set_server(server, true, SD_ID128_NULL);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_set_anonymous(server, true);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_start(server);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_new(&client);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_set_fd(client, pair[1], pair[1]);
+        if (r < 0)
+                return r;
+        pair[1] = -EBADF;
+
+        r = sd_bus_set_anonymous(client, true);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_start(client);
+        if (r < 0)
+                return r;
+
+        *ret_server = TAKE_PTR(server);
+        *ret_client = TAKE_PTR(client);
+        return 0;
+}
+
+static int wait_for_killed_signal(sd_bus *server, sd_bus *client, const char *cgroup_path, const char *reason) {
+        int r;
+
+        assert(server);
+        assert(client);
+        assert(cgroup_path);
+        assert(reason);
+
+        for (size_t i = 0; i < 200; i++) {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m_client = NULL;
+
+                r = sd_bus_process(server, NULL);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_process(client, &m_client);
+                if (r < 0)
+                        return r;
+
+                if (m_client && sd_bus_message_is_signal(m_client, "org.freedesktop.oom1.Manager", "Killed")) {
+                        const char *got_cgroup, *got_reason;
+
+                        r = sd_bus_message_read(m_client, "ss", &got_cgroup, &got_reason);
+                        if (r < 0)
+                                return r;
+
+                        if (!streq(got_cgroup, cgroup_path))
+                                return -ENOMSG;
+                        if (!streq(got_reason, reason))
+                                return -ENOMSG;
+
+                        return 0;
+                }
+
+                r = sd_bus_wait(client, 50 * USEC_PER_MSEC);
+                if (r < 0)
+                        return r;
+        }
+
+        return -ETIMEDOUT;
+}
+
 TEST(oomd_cgroup_kill) {
         _cleanup_free_ char *subcgroup = NULL;
         int r;
@@ -117,6 +219,54 @@ TEST(oomd_cgroup_kill) {
         ASSERT_OK(cg_trim(subcgroup, /* delete_root */ true));
 }
 
+TEST(oomd_cgroup_kill_signal_reason) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *server = NULL, *client = NULL;
+        _cleanup_free_ char *subcgroup = NULL;
+        static const char *reasons[] = {
+                "memory-used",
+                "memory-pressure",
+        };
+        Manager m = {};
+        int r;
+
+        r = enter_cgroup_root_cached();
+        if (r < 0)
+                return (void) log_tests_skipped_errno(r, "Failed to enter cgroup root");
+
+        ASSERT_NOT_NULL(subcgroup = path_join(cgroup, "oomdkillsignaltest"));
+        ASSERT_OK(cg_trim(subcgroup, /* delete_root= */ true));
+        ASSERT_OK(cg_create(subcgroup));
+
+        ASSERT_OK(setup_local_oomd_bus(&server, &client));
+        m.bus = server;
+
+        for (size_t i = 0; i < ELEMENTSOF(reasons); i++) {
+                _cleanup_(pidref_done) PidRef one = PIDREF_NULL, two = PIDREF_NULL;
+                const char *reason = reasons[i];
+
+                ASSERT_OK(fork_and_sleep(5, &one));
+                ASSERT_OK(cg_attach(subcgroup, one.pid));
+                ASSERT_OK(fork_and_sleep(5, &two));
+                ASSERT_OK(cg_attach(subcgroup, two.pid));
+
+                ASSERT_OK_POSITIVE(oomd_cgroup_kill(&m, &(OomdCGroupContext) { .path = subcgroup }, /* recurse= */ false, reason));
+                ASSERT_OK(wait_for_killed_signal(server, client, subcgroup, reason));
+
+                /* Cleanup isn't instantaneous, so give it some grace */
+                bool empty = false;
+                for (size_t t = 0; t < 100; t++) {
+                        usleep_safe(100 * USEC_PER_MSEC);
+                        if (ASSERT_OK(cg_is_empty(subcgroup)) > 0) {
+                                empty = true;
+                                break;
+                        }
+                }
+                ASSERT_TRUE(empty);
+        }
+
+        ASSERT_OK(cg_trim(subcgroup, /* delete_root= */ true));
+}
+
 TEST(oomd_cgroup_context_acquire_and_insert) {
         _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
         _cleanup_(oomd_cgroup_context_unrefp) OomdCGroupContext *ctx = NULL;