oomd: Add regression tests to check Killed notification gives a reason
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user