Blame src/core/tests/test-core-with-expect.c

Packit Service 5ffa24
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit Service 5ffa24
/*
Packit Service 5ffa24
 * Copyright (C) 2014 Red Hat, Inc.
Packit Service 5ffa24
 */
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-default.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include <time.h>
Packit Service 5ffa24
#include <sys/types.h>
Packit Service 5ffa24
#include <sys/wait.h>
Packit Service 5ffa24
#include <fcntl.h>
Packit Service 5ffa24
Packit Service 5ffa24
#include "NetworkManagerUtils.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-test-utils-core.h"
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_monotonic_timestamp_as_boottime(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    gint64          timestamp_nsec_per_tick, now, now_boottime, now_boottime_2, now_boottime_3;
Packit Service 5ffa24
    struct timespec tp;
Packit Service 5ffa24
    clockid_t       clockid;
Packit Service 5ffa24
    guint           i;
Packit Service 5ffa24
Packit Service 5ffa24
    if (clock_gettime(CLOCK_BOOTTIME, &tp) != 0 && errno == EINVAL)
Packit Service 5ffa24
        clockid = CLOCK_MONOTONIC;
Packit Service 5ffa24
    else
Packit Service 5ffa24
        clockid = CLOCK_BOOTTIME;
Packit Service 5ffa24
Packit Service 5ffa24
    for (i = 0; i < 10; i++) {
Packit Service 5ffa24
        if (clock_gettime(clockid, &tp) != 0)
Packit Service 5ffa24
            g_assert_not_reached();
Packit Service 5ffa24
        now_boottime = (((gint64) tp.tv_sec) * NM_UTILS_NSEC_PER_SEC) + ((gint64) tp.tv_nsec);
Packit Service 5ffa24
Packit Service 5ffa24
        now = nm_utils_get_monotonic_timestamp_nsec();
Packit Service 5ffa24
Packit Service 5ffa24
        now_boottime_2 = nm_utils_monotonic_timestamp_as_boottime(now, 1);
Packit Service 5ffa24
        g_assert_cmpint(now_boottime_2, >=, 0);
Packit Service 5ffa24
        g_assert_cmpint(now_boottime_2, >=, now_boottime);
Packit Service 5ffa24
        g_assert_cmpint(now_boottime_2 - now_boottime, <=, NM_UTILS_NSEC_PER_SEC / 10);
Packit Service 5ffa24
Packit Service 5ffa24
        g_assert_cmpint(now, ==, nm_utils_monotonic_timestamp_from_boottime(now_boottime_2, 1));
Packit Service 5ffa24
Packit Service 5ffa24
        for (timestamp_nsec_per_tick = 1; timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC;
Packit Service 5ffa24
             timestamp_nsec_per_tick *= 10) {
Packit Service 5ffa24
            now_boottime_3 = nm_utils_monotonic_timestamp_as_boottime(now / timestamp_nsec_per_tick,
Packit Service 5ffa24
                                                                      timestamp_nsec_per_tick);
Packit Service 5ffa24
Packit Service 5ffa24
            g_assert_cmpint(now_boottime_2 / timestamp_nsec_per_tick, ==, now_boottime_3);
Packit Service 5ffa24
            g_assert_cmpint(now / timestamp_nsec_per_tick,
Packit Service 5ffa24
                            ==,
Packit Service 5ffa24
                            nm_utils_monotonic_timestamp_from_boottime(now_boottime_3,
Packit Service 5ffa24
                                                                       timestamp_nsec_per_tick));
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
struct test_nm_utils_kill_child_async_data {
Packit Service 5ffa24
    GMainLoop *loop;
Packit Service 5ffa24
    pid_t      pid;
Packit Service 5ffa24
    gboolean   called;
Packit Service 5ffa24
    gboolean   expected_success;
Packit Service 5ffa24
    const int *expected_child_status;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_kill_child_async_cb(pid_t pid, gboolean success, int child_status, void *user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    struct test_nm_utils_kill_child_async_data *data = user_data;
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(success == !!data->expected_success);
Packit Service 5ffa24
    g_assert(pid == data->pid);
Packit Service 5ffa24
    if (data->expected_child_status)
Packit Service 5ffa24
        g_assert_cmpint(*data->expected_child_status, ==, child_status);
Packit Service 5ffa24
    if (!success)
Packit Service 5ffa24
        g_assert_cmpint(child_status, ==, -1);
Packit Service 5ffa24
Packit Service 5ffa24
    data->called = TRUE;
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(data->loop);
Packit Service 5ffa24
    g_main_loop_quit(data->loop);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static gboolean
Packit Service 5ffa24
test_nm_utils_kill_child_async_fail_cb(void *user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    g_assert_not_reached();
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_kill_child_async_do(const char *name,
Packit Service 5ffa24
                                  pid_t       pid,
Packit Service 5ffa24
                                  int         sig,
Packit Service 5ffa24
                                  guint32     wait_before_kill_msec,
Packit Service 5ffa24
                                  gboolean    expected_success,
Packit Service 5ffa24
                                  const int * expected_child_status)
Packit Service 5ffa24
{
Packit Service 5ffa24
    gboolean                                   success;
Packit Service 5ffa24
    struct test_nm_utils_kill_child_async_data data = {};
Packit Service 5ffa24
    int                                        timeout_id;
Packit Service 5ffa24
Packit Service 5ffa24
    data.pid                   = pid;
Packit Service 5ffa24
    data.expected_success      = expected_success;
Packit Service 5ffa24
    data.expected_child_status = expected_child_status;
Packit Service 5ffa24
Packit Service 5ffa24
    nm_utils_kill_child_async(pid,
Packit Service 5ffa24
                              sig,
Packit Service 5ffa24
                              LOGD_CORE,
Packit Service 5ffa24
                              name,
Packit Service 5ffa24
                              wait_before_kill_msec,
Packit Service 5ffa24
                              test_nm_utils_kill_child_async_cb,
Packit Service 5ffa24
                              &data);
Packit Service 5ffa24
    g_assert(!data.called);
Packit Service 5ffa24
Packit Service 5ffa24
    timeout_id = g_timeout_add_seconds(5, test_nm_utils_kill_child_async_fail_cb, &data);
Packit Service 5ffa24
Packit Service 5ffa24
    data.loop = g_main_loop_new(NULL, FALSE);
Packit Service 5ffa24
    g_main_loop_run(data.loop);
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(data.called);
Packit Service 5ffa24
    success = g_source_remove(timeout_id);
Packit Service 5ffa24
    g_assert(success);
Packit Service 5ffa24
Packit Service 5ffa24
    g_main_loop_unref(data.loop);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_kill_child_sync_do(const char *name,
Packit Service 5ffa24
                                 pid_t       pid,
Packit Service 5ffa24
                                 int         sig,
Packit Service 5ffa24
                                 guint32     wait_before_kill_msec,
Packit Service 5ffa24
                                 gboolean    expected_success,
Packit Service 5ffa24
                                 const int * expected_child_status)
Packit Service 5ffa24
{
Packit Service 5ffa24
    gboolean success;
Packit Service 5ffa24
    int      child_status = -1;
Packit Service 5ffa24
Packit Service 5ffa24
    success = nm_utils_kill_child_sync(pid,
Packit Service 5ffa24
                                       sig,
Packit Service 5ffa24
                                       LOGD_CORE,
Packit Service 5ffa24
                                       name,
Packit Service 5ffa24
                                       &child_status,
Packit Service 5ffa24
                                       wait_before_kill_msec,
Packit Service 5ffa24
                                       0);
Packit Service 5ffa24
    g_assert(success == !!expected_success);
Packit Service 5ffa24
    if (expected_child_status)
Packit Service 5ffa24
        g_assert_cmpint(*expected_child_status, ==, child_status);
Packit Service 5ffa24
Packit Service 5ffa24
    g_test_assert_expected_messages();
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static pid_t
Packit Service 5ffa24
test_nm_utils_kill_child_spawn(char **argv, gboolean do_not_reap_child)
Packit Service 5ffa24
{
Packit Service 5ffa24
    GError *error = NULL;
Packit Service 5ffa24
    int     success;
Packit Service 5ffa24
    GPid    child_pid;
Packit Service 5ffa24
Packit Service 5ffa24
    success =
Packit Service 5ffa24
        g_spawn_async(NULL,
Packit Service 5ffa24
                      argv,
Packit Service 5ffa24
                      NULL,
Packit Service 5ffa24
                      G_SPAWN_SEARCH_PATH | (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0),
Packit Service 5ffa24
                      NULL,
Packit Service 5ffa24
                      NULL,
Packit Service 5ffa24
                      &child_pid,
Packit Service 5ffa24
                      &error);
Packit Service 5ffa24
    g_assert(success && !error);
Packit Service 5ffa24
    return child_pid;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static pid_t
Packit Service 5ffa24
do_test_nm_utils_kill_child_create_and_join_pgroup(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int   err, tmp = 0;
Packit Service 5ffa24
    int   pipefd[2];
Packit Service 5ffa24
    pid_t pgid;
Packit Service 5ffa24
Packit Service 5ffa24
    err = pipe2(pipefd, O_CLOEXEC);
Packit Service 5ffa24
    g_assert(err == 0);
Packit Service 5ffa24
Packit Service 5ffa24
    pgid = fork();
Packit Service 5ffa24
    g_assert(pgid >= 0);
Packit Service 5ffa24
Packit Service 5ffa24
    if (pgid == 0) {
Packit Service 5ffa24
        /* child process... */
Packit Service 5ffa24
        nm_close(pipefd[0]);
Packit Service 5ffa24
Packit Service 5ffa24
        err = setpgid(0, 0);
Packit Service 5ffa24
        g_assert(err == 0);
Packit Service 5ffa24
Packit Service 5ffa24
        err = write(pipefd[1], &tmp, sizeof(tmp));
Packit Service 5ffa24
        g_assert(err == sizeof(tmp));
Packit Service 5ffa24
Packit Service 5ffa24
        nm_close(pipefd[1]);
Packit Service 5ffa24
        exit(0);
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    nm_close(pipefd[1]);
Packit Service 5ffa24
Packit Service 5ffa24
    err = read(pipefd[0], &tmp, sizeof(tmp));
Packit Service 5ffa24
    g_assert(err == sizeof(tmp));
Packit Service 5ffa24
Packit Service 5ffa24
    nm_close(pipefd[0]);
Packit Service 5ffa24
Packit Service 5ffa24
    err = setpgid(0, pgid);
Packit Service 5ffa24
    g_assert(err == 0);
Packit Service 5ffa24
Packit Service 5ffa24
    do {
Packit Service 5ffa24
        err = waitpid(pgid, &tmp, 0);
Packit Service 5ffa24
    } while (err == -1 && errno == EINTR);
Packit Service 5ffa24
    g_assert(err == pgid);
Packit Service 5ffa24
    g_assert(WIFEXITED(tmp) && WEXITSTATUS(tmp) == 0);
Packit Service 5ffa24
Packit Service 5ffa24
    return pgid;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
#define TEST_TOKEN "nm_test_kill_child_process"
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
do_test_nm_utils_kill_child(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    GLogLevelFlags fatal_mask;
Packit Service 5ffa24
    char *         argv_watchdog[] = {
Packit Service 5ffa24
        "bash",
Packit Service 5ffa24
        "-c",
Packit Service 5ffa24
        "sleep 4; "
Packit Service 5ffa24
        "kill -KILL 0; #watchdog for #" TEST_TOKEN,
Packit Service 5ffa24
        NULL,
Packit Service 5ffa24
    };
Packit Service 5ffa24
    char *argv1[] = {
Packit Service 5ffa24
        "bash",
Packit Service 5ffa24
        "-c",
Packit Service 5ffa24
        "trap \"sleep 0.5; exit 10\" EXIT; "
Packit Service 5ffa24
        "sleep 100000; exit $? #" TEST_TOKEN,
Packit Service 5ffa24
        NULL,
Packit Service 5ffa24
    };
Packit Service 5ffa24
    char *argv2[] = {
Packit Service 5ffa24
        "bash",
Packit Service 5ffa24
        "-c",
Packit Service 5ffa24
        "exit 47; #" TEST_TOKEN,
Packit Service 5ffa24
        NULL,
Packit Service 5ffa24
    };
Packit Service 5ffa24
    char *argv3[] = {
Packit Service 5ffa24
        "bash",
Packit Service 5ffa24
        "-c",
Packit Service 5ffa24
        "trap \"exit 47\" TERM; while true; do :; done; #" TEST_TOKEN,
Packit Service 5ffa24
        NULL,
Packit Service 5ffa24
    };
Packit Service 5ffa24
    char *argv4[] = {
Packit Service 5ffa24
        "bash",
Packit Service 5ffa24
        "-c",
Packit Service 5ffa24
        "trap \"while true; do :; done\" TERM; while true; do :; done; #" TEST_TOKEN,
Packit Service 5ffa24
        NULL,
Packit Service 5ffa24
    };
Packit Service 5ffa24
    pid_t pid1a_1, pid1a_2, pid1a_3, pid2a, pid3a, pid4a;
Packit Service 5ffa24
    pid_t pid1s_1, pid1s_2, pid1s_3, pid2s, pid3s, pid4s;
Packit Service 5ffa24
Packit Service 5ffa24
    const int expected_exit_47     = 12032; /* exit with status 47 */
Packit Service 5ffa24
    const int expected_signal_TERM = SIGTERM;
Packit Service 5ffa24
    const int expected_signal_KILL = SIGKILL;
Packit Service 5ffa24
Packit Service 5ffa24
    test_nm_utils_kill_child_spawn(argv_watchdog, FALSE);
Packit Service 5ffa24
Packit Service 5ffa24
    pid1s_1 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid1s_2 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid1s_3 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid2s   = test_nm_utils_kill_child_spawn(argv2, TRUE);
Packit Service 5ffa24
    pid3s   = test_nm_utils_kill_child_spawn(argv3, TRUE);
Packit Service 5ffa24
    pid4s   = test_nm_utils_kill_child_spawn(argv4, TRUE);
Packit Service 5ffa24
Packit Service 5ffa24
    pid1a_1 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid1a_2 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid1a_3 = test_nm_utils_kill_child_spawn(argv1, TRUE);
Packit Service 5ffa24
    pid2a   = test_nm_utils_kill_child_spawn(argv2, TRUE);
Packit Service 5ffa24
    pid3a   = test_nm_utils_kill_child_spawn(argv3, TRUE);
Packit Service 5ffa24
    pid4a   = test_nm_utils_kill_child_spawn(argv4, TRUE);
Packit Service 5ffa24
Packit Service 5ffa24
    /* give processes time to start (and potentially block signals) ... */
Packit Service 5ffa24
    g_usleep(G_USEC_PER_SEC / 10);
Packit Service 5ffa24
Packit Service 5ffa24
    fatal_mask = g_log_set_always_fatal(G_LOG_FATAL_MASK);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-1' (*): waiting up to 3000 milliseconds "
Packit Service 5ffa24
                          "for process to terminate normally after sending SIGTERM (15)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-1' (*): after sending SIGTERM (15), "
Packit Service 5ffa24
                          "process * exited by signal 15 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-1-1",
Packit Service 5ffa24
                                     pid1s_1,
Packit Service 5ffa24
                                     SIGTERM,
Packit Service 5ffa24
                                     3000,
Packit Service 5ffa24
                                     TRUE,
Packit Service 5ffa24
                                     &expected_signal_TERM);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-2' (*): waiting for process to terminate "
Packit Service 5ffa24
                          "after sending SIGKILL (9)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-2' (*): after sending SIGKILL (9), process "
Packit Service 5ffa24
                          "* exited by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-1-2",
Packit Service 5ffa24
                                     pid1s_2,
Packit Service 5ffa24
                                     SIGKILL,
Packit Service 5ffa24
                                     1000 / 2,
Packit Service 5ffa24
                                     TRUE,
Packit Service 5ffa24
                                     &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-3' (*): waiting up to 1 milliseconds for "
Packit Service 5ffa24
                          "process to terminate normally after sending no signal (0)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-3' (*): sending SIGKILL...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-1-3' (*): after sending no signal (0) and "
Packit Service 5ffa24
                          "SIGKILL, process * exited by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-1-3", pid1s_3, 0, 1, TRUE, &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-s-2' (*): process * already terminated normally with status 47");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-2", pid2s, SIGTERM, 3000, TRUE, &expected_exit_47);
Packit Service 5ffa24
Packit Service 5ffa24
    /* send invalid signal. */
Packit Service 5ffa24
    NMTST_EXPECT_NM_ERROR("kill child process 'test-s-3-0' (*): failed to send Unexpected signal: "
Packit Service 5ffa24
                          "Invalid argument (22)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-3-0", pid3s, -1, 0, FALSE, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    /* really kill pid3s */
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-3-1' (*): waiting up to 3000 milliseconds "
Packit Service 5ffa24
                          "for process to terminate normally after sending SIGTERM (15)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-3-1' (*): after sending SIGTERM (15), "
Packit Service 5ffa24
                          "process * exited normally with status 47 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-3-1", pid3s, SIGTERM, 3000, TRUE, &expected_exit_47);
Packit Service 5ffa24
Packit Service 5ffa24
    /* pid3s should not be a valid process, hence the call should fail. Note, that there
Packit Service 5ffa24
     * is a race here. */
Packit Service 5ffa24
    NMTST_EXPECT_NM_ERROR(
Packit Service 5ffa24
        "kill child process 'test-s-3-2' (*): failed due to unexpected return value -1 by waitpid "
Packit Service 5ffa24
        "(No child process*, 10) after sending no signal (0)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-3-2", pid3s, 0, 0, FALSE, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): waiting up to 1 milliseconds for "
Packit Service 5ffa24
                          "process to terminate normally after sending SIGTERM (15)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): sending SIGKILL...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): after sending SIGTERM (15) and "
Packit Service 5ffa24
                          "SIGKILL, process * exited by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_sync_do("test-s-4", pid4s, SIGTERM, 1, TRUE, &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-1-1' (*): wait for process to terminate "
Packit Service 5ffa24
                          "after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-1-1' (*): terminated by signal 15 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-1-1",
Packit Service 5ffa24
                                      pid1a_1,
Packit Service 5ffa24
                                      SIGTERM,
Packit Service 5ffa24
                                      3000,
Packit Service 5ffa24
                                      TRUE,
Packit Service 5ffa24
                                      &expected_signal_TERM);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-1-2' (*): wait for process to terminate "
Packit Service 5ffa24
                          "after sending SIGKILL (9)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-1-2' (*): terminated by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-1-2",
Packit Service 5ffa24
                                      pid1a_2,
Packit Service 5ffa24
                                      SIGKILL,
Packit Service 5ffa24
                                      1000 / 2,
Packit Service 5ffa24
                                      TRUE,
Packit Service 5ffa24
                                      &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-1-3' (*): wait for process to terminate "
Packit Service 5ffa24
                          "after sending no signal (0) (send SIGKILL in 1 milliseconds)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-1-3' (*): process not terminated after * "
Packit Service 5ffa24
                          "usec. Sending SIGKILL signal");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-1-3' (*): terminated by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-1-3", pid1a_3, 0, 1, TRUE, &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-2' (*): process * already terminated normally with status 47");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-2' (*): invoke callback: terminated normally with status 47");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-2", pid2a, SIGTERM, 3000, TRUE, &expected_exit_47);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_ERROR("kill child process 'test-a-3-0' (*): unexpected error sending "
Packit Service 5ffa24
                          "Unexpected signal: Invalid argument (22)");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-3-0' (*): invoke callback: killing child failed");
Packit Service 5ffa24
    /* coverity[negative_returns] */
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-3-0", pid3a, -1, 1000 / 2, FALSE, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-3-1' (*): wait for process to terminate "
Packit Service 5ffa24
                          "after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-3-1' (*): terminated normally with status 47 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-3-1", pid3a, SIGTERM, 3000, TRUE, &expected_exit_47);
Packit Service 5ffa24
Packit Service 5ffa24
    /* pid3a should not be a valid process, hence the call should fail. Note, that there
Packit Service 5ffa24
     * is a race here. */
Packit Service 5ffa24
    NMTST_EXPECT_NM_ERROR(
Packit Service 5ffa24
        "kill child process 'test-a-3-2' (*): failed due to unexpected return value -1 by waitpid "
Packit Service 5ffa24
        "(No child process*, 10) after sending no signal (0)");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-3-2' (*): invoke callback: killing child failed");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-3-2", pid3a, 0, 0, FALSE, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-4' (*): wait for process to terminate after "
Packit Service 5ffa24
                          "sending SIGTERM (15) (send SIGKILL in 1 milliseconds)...");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-4' (*): process not terminated after * usec. "
Packit Service 5ffa24
                          "Sending SIGKILL signal");
Packit Service 5ffa24
    NMTST_EXPECT_NM_DEBUG(
Packit Service 5ffa24
        "kill child process 'test-a-4' (*): terminated by signal 9 (* usec elapsed)");
Packit Service 5ffa24
    test_nm_utils_kill_child_async_do("test-a-4", pid4a, SIGTERM, 1, TRUE, &expected_signal_KILL);
Packit Service 5ffa24
Packit Service 5ffa24
    g_log_set_always_fatal(fatal_mask);
Packit Service 5ffa24
Packit Service 5ffa24
    g_test_assert_expected_messages();
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_kill_child(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int   err;
Packit Service 5ffa24
    int   exit_status;
Packit Service 5ffa24
    pid_t gpid;
Packit Service 5ffa24
    pid_t child_pid;
Packit Service 5ffa24
Packit Service 5ffa24
    /* the tests spawns several processes, we want to clean them up
Packit Service 5ffa24
     * by sending a SIGKILL to the process group.
Packit Service 5ffa24
     *
Packit Service 5ffa24
     * The current process might be a session leader, which prevents it from
Packit Service 5ffa24
     * creating a new process group. Hence, first fork and let the child
Packit Service 5ffa24
     * create a new process group, run the tests, and kill all pending
Packit Service 5ffa24
     * processes. */
Packit Service 5ffa24
    child_pid = fork();
Packit Service 5ffa24
    g_assert(child_pid >= 0);
Packit Service 5ffa24
Packit Service 5ffa24
    if (child_pid == 0) {
Packit Service 5ffa24
        gpid = do_test_nm_utils_kill_child_create_and_join_pgroup();
Packit Service 5ffa24
Packit Service 5ffa24
        do_test_nm_utils_kill_child();
Packit Service 5ffa24
Packit Service 5ffa24
        err = setpgid(0, 0);
Packit Service 5ffa24
        g_assert(err == 0);
Packit Service 5ffa24
Packit Service 5ffa24
        kill(-gpid, SIGKILL);
Packit Service 5ffa24
Packit Service 5ffa24
        exit(0);
Packit Service 5ffa24
    };
Packit Service 5ffa24
Packit Service 5ffa24
    do {
Packit Service 5ffa24
        err = waitpid(child_pid, &exit_status, 0);
Packit Service 5ffa24
    } while (err == -1 && errno == EINTR);
Packit Service 5ffa24
    g_assert(err == child_pid);
Packit Service 5ffa24
    if (WIFEXITED(exit_status))
Packit Service 5ffa24
        g_assert_cmpint(WEXITSTATUS(exit_status), ==, 0);
Packit Service 5ffa24
    else {
Packit Service 5ffa24
        g_assert_cmpint(exit_status, ==, 0);
Packit Service 5ffa24
        g_assert_not_reached();
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
_remove_at_indexes_init_random_idx(GArray *idx, guint array_len, guint idx_len)
Packit Service 5ffa24
{
Packit Service 5ffa24
    GRand *       rand = nmtst_get_rand();
Packit Service 5ffa24
    gs_free char *mask = NULL;
Packit Service 5ffa24
    guint         i, max_test_idx;
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(idx);
Packit Service 5ffa24
    g_assert(array_len > 0);
Packit Service 5ffa24
    g_assert(idx_len >= 1 && idx_len <= array_len);
Packit Service 5ffa24
Packit Service 5ffa24
    mask = g_new0(char, array_len);
Packit Service 5ffa24
Packit Service 5ffa24
    max_test_idx = array_len - 1;
Packit Service 5ffa24
    for (i = 0; i < idx_len; i++) {
Packit Service 5ffa24
        guint itest;
Packit Service 5ffa24
Packit Service 5ffa24
        /* find a index itest that is not yet taken */
Packit Service 5ffa24
        if (max_test_idx == 0)
Packit Service 5ffa24
            itest = 0;
Packit Service 5ffa24
        else
Packit Service 5ffa24
            itest = g_rand_int_range(rand, 0, max_test_idx);
Packit Service 5ffa24
        while (itest < array_len && mask[itest])
Packit Service 5ffa24
            itest++;
Packit Service 5ffa24
        g_assert(itest <= max_test_idx);
Packit Service 5ffa24
        g_assert(!mask[itest]);
Packit Service 5ffa24
Packit Service 5ffa24
        mask[itest] = TRUE;
Packit Service 5ffa24
        if (itest == max_test_idx) {
Packit Service 5ffa24
            g_assert(max_test_idx > 0 || i == idx_len - 1);
Packit Service 5ffa24
Packit Service 5ffa24
            if (max_test_idx == 0)
Packit Service 5ffa24
                g_assert_cmpint(i, ==, idx_len - 1);
Packit Service 5ffa24
            else {
Packit Service 5ffa24
                max_test_idx--;
Packit Service 5ffa24
                while (max_test_idx > 0 && mask[max_test_idx])
Packit Service 5ffa24
                    max_test_idx--;
Packit Service 5ffa24
                if (mask[max_test_idx])
Packit Service 5ffa24
                    g_assert_cmpint(i, ==, idx_len - 1);
Packit Service 5ffa24
            }
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    g_array_set_size(idx, 0);
Packit Service 5ffa24
    for (i = 0; i < array_len; i++) {
Packit Service 5ffa24
        if (mask[i])
Packit Service 5ffa24
            g_array_append_val(idx, i);
Packit Service 5ffa24
    }
Packit Service 5ffa24
    g_assert_cmpint(idx->len, ==, idx_len);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_array_remove_at_indexes(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    gs_unref_array GArray *idx = NULL, *array = NULL;
Packit Service 5ffa24
    gs_unref_hashtable GHashTable *unique = NULL;
Packit Service 5ffa24
    guint                          i_len, i_idx_len, i_rnd, i;
Packit Service 5ffa24
Packit Service 5ffa24
    idx    = g_array_new(FALSE, FALSE, sizeof(guint));
Packit Service 5ffa24
    array  = g_array_new(FALSE, FALSE, sizeof(gssize));
Packit Service 5ffa24
    unique = g_hash_table_new(nm_direct_hash, NULL);
Packit Service 5ffa24
    for (i_len = 1; i_len < 20; i_len++) {
Packit Service 5ffa24
        for (i_idx_len = 1; i_idx_len <= i_len; i_idx_len++) {
Packit Service 5ffa24
            for (i_rnd = 0; i_rnd < 20; i_rnd++) {
Packit Service 5ffa24
                _remove_at_indexes_init_random_idx(idx, i_len, i_idx_len);
Packit Service 5ffa24
                g_array_set_size(array, i_len);
Packit Service 5ffa24
                for (i = 0; i < i_len; i++)
Packit Service 5ffa24
                    g_array_index(array, gssize, i) = i;
Packit Service 5ffa24
Packit Service 5ffa24
                nm_utils_array_remove_at_indexes(array, &g_array_index(idx, guint, 0), i_idx_len);
Packit Service 5ffa24
Packit Service 5ffa24
                g_hash_table_remove_all(unique);
Packit Service 5ffa24
                /* ensure that all the indexes are still unique */
Packit Service 5ffa24
                for (i = 0; i < array->len; i++)
Packit Service 5ffa24
                    g_hash_table_add(unique, GUINT_TO_POINTER(g_array_index(array, gssize, i)));
Packit Service 5ffa24
                g_assert_cmpint(g_hash_table_size(unique), ==, array->len);
Packit Service 5ffa24
Packit Service 5ffa24
                for (i = 0; i < idx->len; i++)
Packit Service 5ffa24
                    g_hash_table_add(unique, GUINT_TO_POINTER(g_array_index(idx, guint, i)));
Packit Service 5ffa24
                g_assert_cmpint(g_hash_table_size(unique), ==, i_len);
Packit Service 5ffa24
Packit Service 5ffa24
                /* ensure proper sort order in array */
Packit Service 5ffa24
                for (i = 0; i < array->len; i++) {
Packit Service 5ffa24
                    gssize i1 = g_array_index(array, gssize, i);
Packit Service 5ffa24
Packit Service 5ffa24
                    g_assert(i1 >= 0 && i1 < i_len);
Packit Service 5ffa24
                    if (i > 0) {
Packit Service 5ffa24
                        gsize i0 = g_array_index(array, gssize, i - 1);
Packit Service 5ffa24
                        g_assert_cmpint(i0, <, i1);
Packit Service 5ffa24
                    }
Packit Service 5ffa24
                }
Packit Service 5ffa24
            }
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_ethernet_address_is_valid(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str(NULL));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid(NULL));
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("FF:FF:FF:FF:FF:FF"));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("00:00:00:00:00:00"));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("44:44:44:44:44:44"));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("00:30:b4:00:00:00"));
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str(""));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("1"));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("2"));
Packit Service 5ffa24
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid(&NM_ETHER_ADDR_INIT(0x00, 0x30, 0xb4, 0x00, 0x00, 0x00)));
Packit Service 5ffa24
    g_assert(nm_ether_addr_is_valid(&NM_ETHER_ADDR_INIT(0x00, 0x30, 0xb4, 0x00, 0x00, 0x01)));
Packit Service 5ffa24
Packit Service 5ffa24
    /* some Broad cast addresses (with MSB of first octet set). */
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid_str("57:44:44:44:44:44"));
Packit Service 5ffa24
    g_assert(nm_ether_addr_is_valid_str("56:44:44:44:44:44"));
Packit Service 5ffa24
    g_assert(!nm_ether_addr_is_valid(&NM_ETHER_ADDR_INIT(0x03, 0x30, 0xb4, 0x00, 0x00, 0x00)));
Packit Service 5ffa24
    g_assert(nm_ether_addr_is_valid(&NM_ETHER_ADDR_INIT(0x02, 0x30, 0xb4, 0x00, 0x00, 0x01)));
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
test_nm_utils_new_vlan_name(void)
Packit Service 5ffa24
{
Packit Service 5ffa24
    guint       i, j;
Packit Service 5ffa24
    const char *parent_names[] = {
Packit Service 5ffa24
        "a",
Packit Service 5ffa24
        "a2",
Packit Service 5ffa24
        "a23",
Packit Service 5ffa24
        "a23456789",
Packit Service 5ffa24
        "a2345678901",
Packit Service 5ffa24
        "a23456789012",
Packit Service 5ffa24
        "a234567890123",
Packit Service 5ffa24
        "a2345678901234",
Packit Service 5ffa24
        "a23456789012345",
Packit Service 5ffa24
        "a234567890123456",
Packit Service 5ffa24
        "a2345678901234567",
Packit Service 5ffa24
    };
Packit Service 5ffa24
Packit Service 5ffa24
    for (i = 0; i < G_N_ELEMENTS(parent_names); i++) {
Packit Service 5ffa24
        for (j = 0; j < 10; j++) {
Packit Service 5ffa24
            gs_free char *ifname    = NULL;
Packit Service 5ffa24
            gs_free char *vlan_id_s = NULL;
Packit Service 5ffa24
            guint         vlan_id;
Packit Service 5ffa24
Packit Service 5ffa24
            /* Create a random VLAN id between 0 and 4094 */
Packit Service 5ffa24
            vlan_id = nmtst_get_rand_uint32() % 4095;
Packit Service 5ffa24
Packit Service 5ffa24
            vlan_id_s = g_strdup_printf(".%d", vlan_id);
Packit Service 5ffa24
Packit Service 5ffa24
            ifname = nm_utils_new_vlan_name(parent_names[i], vlan_id);
Packit Service 5ffa24
            g_assert(ifname && ifname[0]);
Packit Service 5ffa24
            g_assert_cmpint(strlen(ifname),
Packit Service 5ffa24
                            ==,
Packit Service 5ffa24
                            MIN(15, strlen(parent_names[i]) + strlen(vlan_id_s)));
Packit Service 5ffa24
            g_assert(g_str_has_suffix(ifname, vlan_id_s));
Packit Service 5ffa24
            g_assert(ifname[strlen(ifname) - strlen(vlan_id_s)] == '.');
Packit Service 5ffa24
            g_assert(strncmp(ifname, parent_names[i], strlen(ifname) - strlen(vlan_id_s)) == 0);
Packit Service 5ffa24
            if (!g_str_has_prefix(ifname, parent_names[i]))
Packit Service 5ffa24
                g_assert_cmpint(strlen(ifname), ==, 15);
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
NMTST_DEFINE();
Packit Service 5ffa24
Packit Service 5ffa24
int
Packit Service 5ffa24
main(int argc, char **argv)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nmtst_init_assert_logging(&argc, &argv, "DEBUG", "DEFAULT");
Packit Service 5ffa24
Packit Service 5ffa24
    g_test_add_func("/general/nm_utils_monotonic_timestamp_as_boottime",
Packit Service 5ffa24
                    test_nm_utils_monotonic_timestamp_as_boottime);
Packit Service 5ffa24
    g_test_add_func("/general/nm_utils_kill_child", test_nm_utils_kill_child);
Packit Service 5ffa24
    g_test_add_func("/general/nm_utils_array_remove_at_indexes",
Packit Service 5ffa24
                    test_nm_utils_array_remove_at_indexes);
Packit Service 5ffa24
    g_test_add_func("/general/nm_ethernet_address_is_valid", test_nm_ethernet_address_is_valid);
Packit Service 5ffa24
    g_test_add_func("/general/nm_utils_new_vlan_name", test_nm_utils_new_vlan_name);
Packit Service 5ffa24
Packit Service 5ffa24
    return g_test_run();
Packit Service 5ffa24
}