]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/tests.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / tests.c
index f11b93bee72567237b638d2511a33a593d75ed83..11ea12ed69745665219bde8da8a6ace4f707dc89 100644 (file)
@@ -1,30 +1,26 @@
-/***
-  This file is part of systemd.
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
-  Copyright 2016 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <alloc-util.h>
-#include <fs-util.h>
-#include <libgen.h>
+#include <sched.h>
+#include <signal.h>
 #include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
 #include <util.h>
 
-#include "tests.h"
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the POSIX
+ * version which is really broken. We prefer GNU basename(). */
+#include <libgen.h>
+#undef basename
+
+#include "alloc-util.h"
+#include "env-file.h"
+#include "env-util.h"
+#include "fs-util.h"
+#include "log.h"
 #include "path-util.h"
+#include "strv.h"
+#include "tests.h"
 
 char* setup_fake_runtime_dir(void) {
         char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
@@ -36,22 +32,120 @@ char* setup_fake_runtime_dir(void) {
         return p;
 }
 
-const char* get_exe_relative_testdata_dir(void) {
-        _cleanup_free_ char *exedir = NULL;
-        /* convenience: caller does not need to free result */
-        static char testdir[PATH_MAX];
+static void load_testdata_env(void) {
+        static bool called = false;
+        _cleanup_free_ char *s = NULL;
+        _cleanup_free_ char *envpath = NULL;
+        _cleanup_strv_free_ char **pairs = NULL;
+        char **k, **v;
+
+        if (called)
+                return;
+        called = true;
+
+        assert_se(readlink_and_make_absolute("/proc/self/exe", &s) >= 0);
+        dirname(s);
+
+        envpath = path_join(s, "systemd-runtest.env");
+        if (load_env_file_pairs(NULL, envpath, &pairs) < 0)
+                return;
+
+        STRV_FOREACH_PAIR(k, v, pairs)
+                setenv(*k, *v, 0);
+}
+
+const char* get_testdata_dir(void) {
+        const char *env;
+
+        load_testdata_env();
+
+        /* if the env var is set, use that */
+        env = getenv("SYSTEMD_TEST_DATA");
+        if (!env)
+                env = SYSTEMD_TEST_DATA;
+        if (access(env, F_OK) < 0) {
+                fprintf(stderr, "ERROR: $SYSTEMD_TEST_DATA directory [%s] does not exist\n", env);
+                exit(EXIT_FAILURE);
+        }
+
+        return env;
+}
+
+const char* get_catalog_dir(void) {
+        const char *env;
+
+        load_testdata_env();
+
+        /* if the env var is set, use that */
+        env = getenv("SYSTEMD_CATALOG_DIR");
+        if (!env)
+                env = SYSTEMD_CATALOG_DIR;
+        if (access(env, F_OK) < 0) {
+                fprintf(stderr, "ERROR: $SYSTEMD_CATALOG_DIR directory [%s] does not exist\n", env);
+                exit(EXIT_FAILURE);
+        }
+        return env;
+}
+
+bool slow_tests_enabled(void) {
+        int r;
+
+        r = getenv_bool("SYSTEMD_SLOW_TESTS");
+        if (r >= 0)
+                return r;
+
+        if (r != -ENXIO)
+                log_warning_errno(r, "Cannot parse $SYSTEMD_SLOW_TESTS, ignoring.");
+        return SYSTEMD_SLOW_TESTS_DEFAULT;
+}
+
+void test_setup_logging(int level) {
+        log_set_max_level(level);
+        log_parse_environment();
+        log_open();
+}
+
+int log_tests_skipped(const char *message) {
+        log_notice("%s: %s, skipping tests.",
+                   program_invocation_short_name, message);
+        return EXIT_TEST_SKIP;
+}
+
+int log_tests_skipped_errno(int r, const char *message) {
+        log_notice_errno(r, "%s: %s, skipping tests: %m",
+                         program_invocation_short_name, message);
+        return EXIT_TEST_SKIP;
+}
+
+bool have_namespaces(void) {
+        siginfo_t si = {};
+        pid_t pid;
+
+        /* Checks whether namespaces are available. In some cases they aren't. We do this by calling unshare(), and we
+         * do so in a child process in order not to affect our own process. */
+
+        pid = fork();
+        assert_se(pid >= 0);
+
+        if (pid == 0) {
+                /* child */
+                if (unshare(CLONE_NEWNS) < 0)
+                        _exit(EXIT_FAILURE);
+
+                if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
+                        _exit(EXIT_FAILURE);
+
+                _exit(EXIT_SUCCESS);
+        }
 
-        assert_se(readlink_and_make_absolute("/proc/self/exe", &exedir) >= 0);
+        assert_se(waitid(P_PID, pid, &si, WEXITED) >= 0);
+        assert_se(si.si_code == CLD_EXITED);
 
-        /* Check if we're running from the builddir. If so, use the compiled in path. */
-        if (path_startswith(exedir, ABS_BUILD_DIR))
-                return ABS_SRC_DIR "/test";
+        if (si.si_status == EXIT_SUCCESS)
+                return true;
 
-        /* Try relative path, according to the install-test layout */
-        assert_se(snprintf(testdir, sizeof(testdir), "%s/testdata", dirname(exedir)) > 0);
-        if (access(testdir, F_OK) >= 0)
-                return testdir;
+        if (si.si_status == EXIT_FAILURE)
+                return false;
 
-        fputs("ERROR: Cannot find testdata directory, set $SYSTEMD_TEST_DATA\n", stderr);
-        exit(1);
+        assert_not_reached("unexpected exit code");
 }