oomd: Add regression tests to check Killed notification gives a reason

This commit is contained in:
Chris Down
2026-02-17 14:50:21 +09:00
committed by Yu Watanabe
parent 936d864b0b
commit b10e5a60aa
+150
View 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;