diff options
author | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-26 16:35:12 +0100 |
---|---|---|
committer | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-26 16:35:12 +0100 |
commit | 92c306c8e8329e9d68c52549d75e221fa08b61d9 (patch) | |
tree | a42d8a6284b6b6148b139de4be94fe23a3369033 /src/test | |
parent | acdc1dd584c4c6cf32187adf95d43c4fe87b149f (diff) | |
parent | 1742aae2aa8cd33897250d6fcfbe10928e43eb2f (diff) | |
download | systemd-92c306c8e8329e9d68c52549d75e221fa08b61d9.tar.gz systemd-92c306c8e8329e9d68c52549d75e221fa08b61d9.tar.bz2 systemd-92c306c8e8329e9d68c52549d75e221fa08b61d9.zip |
Merge v240 into tizen
systemd 240
Diffstat (limited to 'src/test')
109 files changed, 4718 insertions, 1450 deletions
diff --git a/src/test/meson.build b/src/test/meson.build index e2b69d44fa..50d001494e 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -6,7 +6,8 @@ test_hashmap_ordered_c = custom_target( input : [awkscript, 'test-hashmap-plain.c'], output : 'test-hashmap-ordered.c', command : [awk, '-f', '@INPUT0@', '@INPUT1@'], - capture : true) + capture : true, + build_by_default : want_tests != 'false') test_include_dir = include_directories('.') @@ -26,14 +27,16 @@ test_libsystemd_sym_c = custom_target( input : [libsystemd_sym_path] + systemd_headers, output : 'test-libsystemd-sym.c', command : [generate_sym_test_py, libsystemd_sym_path] + systemd_headers, - capture : true) + capture : true, + build_by_default : want_tests != 'false') test_libudev_sym_c = custom_target( 'test-libudev-sym.c', input : [libudev_sym_path, libudev_h_path], output : 'test-libudev-sym.c', command : [generate_sym_test_py, '@INPUT0@', '@INPUT1@'], - capture : true) + capture : true, + build_by_default : want_tests != 'false') test_dlopen_c = files('test-dlopen.c') @@ -60,6 +63,16 @@ tests += [ libmount, libblkid]], + [['src/test/test-emergency-action.c'], + [libcore, + libshared], + []], + + [['src/test/test-chown-rec.c'], + [libcore, + libshared], + []], + [['src/test/test-job-type.c'], [libcore, libshared], @@ -81,6 +94,17 @@ tests += [ libblkid], '', 'manual'], + [['src/test/test-nscd-flush.c'], + [libcore, + libshared], + [threads, + librt, + libseccomp, + libselinux, + libmount, + libblkid], + '', 'manual'], + [['src/test/test-loopback.c'], [libcore, libshared], @@ -135,10 +159,18 @@ tests += [ libmount, libblkid]], + [['src/test/test-serialize.c'], + [], + []], + [['src/test/test-utf8.c'], [], []], + [['src/test/test-dev-setup.c'], + [], + []], + [['src/test/test-capability.c'], [], [libcap]], @@ -156,6 +188,10 @@ tests += [ [], []], + [['src/test/test-static-destruct.c'], + [], + []], + [['src/test/test-sigbus.c'], [], []], @@ -188,10 +224,18 @@ tests += [ [], []], + [['src/test/test-json.c'], + [], + []], + [['src/test/test-mount-util.c'], [], []], + [['src/test/test-mountpoint-util.c'], + [], + []], + [['src/test/test-exec-util.c'], [], []], @@ -284,6 +328,10 @@ tests += [ [], []], + [['src/test/test-pretty-print.c'], + [], + []], + [['src/test/test-uid-range.c'], [], []], @@ -392,6 +440,10 @@ tests += [ [], []], + [['src/test/test-set-disable-mempool.c'], + [], + [threads]], + [['src/test/test-bitmap.c'], [], []], @@ -609,6 +661,11 @@ tests += [ [], []], + [['src/test/test-ip-protocol-list.c', + shared_generated_gperf_headers], + [], + []], + [['src/test/test-journal-importer.c'], [], []], @@ -627,7 +684,7 @@ tests += [ libblkid, libkmod, libacl], - '', 'manual'], + '', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'], [['src/test/test-id128.c'], [], @@ -645,7 +702,7 @@ tests += [ [['src/test/test-nss.c'], [], [libdl], - '', 'manual'], + 'ENABLE_NSS', 'manual'], [['src/test/test-umount.c', 'src/core/mount-setup.c', @@ -658,6 +715,10 @@ tests += [ [['src/test/test-bus-util.c'], [], []], + + [['src/test/test-sd-hwdb.c'], + [], + []], ] ############################################################ @@ -756,8 +817,7 @@ tests += [ libshared], [threads, libxz, - liblz4], - '', '', '-DCATALOG_DIR="@0@"'.format(build_catalog_dir)], + liblz4]], [['src/journal/test-compress.c'], [libjournal_core, @@ -782,6 +842,10 @@ tests += [ ############################################################ tests += [ + [['src/libsystemd/sd-bus/test-bus-address.c'], + [], + [threads]], + [['src/libsystemd/sd-bus/test-bus-marshal.c'], [], [threads, @@ -881,6 +945,27 @@ tests += [ [['src/libsystemd/sd-login/test-login.c'], [], []], + + [['src/libsystemd/sd-device/test-sd-device.c'], + [], + []], + + [['src/libsystemd/sd-device/test-sd-device-thread.c'], + [libbasic, + libshared_static, + libsystemd], + [threads]], + + [['src/libsystemd/sd-device/test-udev-device-thread.c'], + [libbasic, + libshared_static, + libudev], + [threads]], + + [['src/libsystemd/sd-device/test-sd-device-monitor.c'], + [], + []], + ] if cxx.found() diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c index 81eb40444b..df879747f5 100644 --- a/src/test/test-acl-util.c +++ b/src/test/test-acl-util.c @@ -7,8 +7,8 @@ #include "acl-util.h" #include "fd-util.h" -#include "fileio.h" #include "string-util.h" +#include "tmpfile-util.h" #include "user-util.h" static void test_add_acls_for_user(void) { @@ -32,7 +32,7 @@ static void test_add_acls_for_user(void) { if (getuid() == 0) { const char *nobody = NOBODY_USER_NAME; - r = get_user_creds(&nobody, &uid, NULL, NULL, NULL); + r = get_user_creds(&nobody, &uid, NULL, NULL, NULL, 0); if (r < 0) uid = 0; } else diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c index 8806744edb..c8ef3295b5 100644 --- a/src/test/test-af-list.c +++ b/src/test/test-af-list.c @@ -16,7 +16,7 @@ static const struct af_name* lookup_af(register const char *str, register GPERF_ int main(int argc, const char *argv[]) { - unsigned int i; + unsigned i; for (i = 0; i < ELEMENTSOF(af_names); i++) { if (af_names[i]) { @@ -27,8 +27,8 @@ int main(int argc, const char *argv[]) { assert_se(af_to_name(af_max()) == NULL); assert_se(af_to_name(-1) == NULL); - assert_se(af_from_name("huddlduddl") == AF_UNSPEC); - assert_se(af_from_name("") == AF_UNSPEC); + assert_se(af_from_name("huddlduddl") == -EINVAL); + assert_se(af_from_name("") == -EINVAL); return 0; } diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c index 6bc0a28a42..8c43bfc750 100644 --- a/src/test/test-architecture.c +++ b/src/test/test-architecture.c @@ -2,6 +2,7 @@ #include "architecture.h" #include "log.h" +#include "tests.h" #include "util.h" #include "virt.h" @@ -9,6 +10,8 @@ int main(int argc, char *argv[]) { int a, v; const char *p; + test_setup_logging(LOG_INFO); + assert_se(architecture_from_string("") < 0); assert_se(architecture_from_string(NULL) < 0); assert_se(architecture_from_string("hoge") < 0); @@ -18,7 +21,7 @@ int main(int argc, char *argv[]) { v = detect_virtualization(); if (IN_SET(v, -EPERM, -EACCES)) - return EXIT_TEST_SKIP; + return log_tests_skipped("Cannot detect virtualization"); assert_se(v >= 0); diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c index 10cd9ebab9..3005fc1b69 100644 --- a/src/test/test-arphrd-list.c +++ b/src/test/test-arphrd-list.c @@ -4,8 +4,8 @@ #include <string.h> #include "macro.h" +#include "missing_network.h" #include "string-util.h" -#include "util.h" _unused_ \ static const struct arphrd_name* lookup_arphrd(register const char *str, register GPERF_LEN_TYPE len); @@ -16,7 +16,7 @@ static const struct arphrd_name* lookup_arphrd(register const char *str, registe int main(int argc, const char *argv[]) { - unsigned int i; + unsigned i; for (i = 1; i < ELEMENTSOF(arphrd_names); i++) { if (arphrd_names[i]) { @@ -27,8 +27,8 @@ int main(int argc, const char *argv[]) { assert_se(arphrd_to_name(arphrd_max()) == NULL); assert_se(arphrd_to_name(0) == NULL); - assert_se(arphrd_from_name("huddlduddl") == 0); - assert_se(arphrd_from_name("") == 0); + assert_se(arphrd_from_name("huddlduddl") == -EINVAL); + assert_se(arphrd_from_name("") == -EINVAL); return 0; } diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c index ffd6da80fe..23b06be19b 100644 --- a/src/test/test-ask-password-api.c +++ b/src/test/test-ask-password-api.c @@ -3,15 +3,17 @@ #include "alloc-util.h" #include "ask-password-api.h" #include "log.h" +#include "strv.h" static void ask_password(void) { int r; - _cleanup_free_ char *ret; + _cleanup_strv_free_ char **ret = NULL; r = ask_password_tty(-1, "hello?", "da key", 0, 0, NULL, &ret); assert(r >= 0); + assert(strv_length(ret) == 1); - log_info("Got %s", ret); + log_info("Got %s", *ret); } int main(int argc, char **argv) { diff --git a/src/test/test-async.c b/src/test/test-async.c index 7c7dfe62da..4f5307889e 100644 --- a/src/test/test-async.c +++ b/src/test/test-async.c @@ -3,8 +3,8 @@ #include <unistd.h> #include "async.h" -#include "fileio.h" #include "macro.h" +#include "tmpfile-util.h" #include "util.h" static bool test_async = false; @@ -32,7 +32,7 @@ int main(int argc, char *argv[]) { assert_se(fcntl(fd, F_GETFD) == -1); assert_se(test_async); - unlink(name); + (void) unlink(name); return 0; } diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c index d2afd92f63..6ae84cd6fc 100644 --- a/src/test/test-barrier.c +++ b/src/test/test-barrier.c @@ -16,6 +16,7 @@ #include "barrier.h" #include "util.h" +#include "tests.h" /* 20ms to test deadlocks; All timings use multiples of this constant as * alarm/sleep timers. If this timeout is too small for slow machines to perform @@ -419,18 +420,10 @@ TEST_BARRIER(test_barrier_pending_exit, TEST_BARRIER_WAIT_SUCCESS(pid2)); int main(int argc, char *argv[]) { - /* - * This test uses real-time alarms and sleeps to test for CPU races - * explicitly. This is highly fragile if your system is under load. We - * already increased the BASE_TIME value to make the tests more robust, - * but that just makes the test take significantly longer. Hence, - * disable the test by default, so it will not break CI. - */ - if (argc < 2) - return EXIT_TEST_SKIP; + test_setup_logging(LOG_INFO); - log_parse_environment(); - log_open(); + if (!slow_tests_enabled()) + return log_tests_skipped("slow tests are disabled"); test_barrier_sync(); test_barrier_wait_next(); diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index ef39304b9f..a79e0cf16b 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -4,22 +4,19 @@ #include "boot-timestamps.h" #include "efivars.h" #include "log.h" +#include "tests.h" #include "util.h" static int test_acpi_fpdt(void) { - usec_t loader_start; - usec_t loader_exit; - char ts_start[FORMAT_TIMESPAN_MAX]; - char ts_exit[FORMAT_TIMESPAN_MAX]; - char ts_span[FORMAT_TIMESPAN_MAX]; + char ts_start[FORMAT_TIMESPAN_MAX], ts_exit[FORMAT_TIMESPAN_MAX], ts_span[FORMAT_TIMESPAN_MAX]; + usec_t loader_start, loader_exit; int r; r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA; - log_full_errno(ok ? LOG_DEBUG : LOG_ERR, - r, "Failed to read ACPI FPDT: %m"); + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read ACPI FPDT: %m"); return ok ? 0 : r; } @@ -31,19 +28,15 @@ static int test_acpi_fpdt(void) { } static int test_efi_loader(void) { - usec_t loader_start; - usec_t loader_exit; - char ts_start[FORMAT_TIMESPAN_MAX]; - char ts_exit[FORMAT_TIMESPAN_MAX]; - char ts_span[FORMAT_TIMESPAN_MAX]; + char ts_start[FORMAT_TIMESPAN_MAX], ts_exit[FORMAT_TIMESPAN_MAX], ts_span[FORMAT_TIMESPAN_MAX]; + usec_t loader_start, loader_exit; int r; r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP; - log_full_errno(ok ? LOG_DEBUG : LOG_ERR, - r, "Failed to read EFI loader data: %m"); + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read EFI loader data: %m"); return ok ? 0 : r; } @@ -56,17 +49,16 @@ static int test_efi_loader(void) { static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; - int r; dual_timestamp fw, l, k; + int r; dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { - bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP; - log_full_errno(ok ? LOG_DEBUG : LOG_ERR, - r, "Failed to read variables: %m"); + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read variables: %m"); return ok ? 0 : r; } @@ -81,8 +73,7 @@ static int test_boot_timestamps(void) { int main(int argc, char* argv[]) { int p, q, r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); p = test_acpi_fpdt(); assert(p >= 0); @@ -91,5 +82,8 @@ int main(int argc, char* argv[]) { r = test_boot_timestamps(); assert(r >= 0); - return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP; + if (p == 0 && q == 0 && r == 0) + return log_tests_skipped("access to firmware variables not possible"); + + return EXIT_SUCCESS; } diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c index 4d89bd46d3..ea5f0f5bc6 100644 --- a/src/test/test-bpf.c +++ b/src/test/test-bpf.c @@ -28,17 +28,13 @@ int main(int argc, char *argv[]) { char log_buf[65535]; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice("cgroupfs not available, skipping tests"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); - assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(set_unit_path(get_testdata_dir()) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &p); @@ -47,16 +43,12 @@ int main(int argc, char *argv[]) { r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn)); assert(r == 0); - if (getuid() != 0) { - log_notice("Not running as root, skipping kernel related tests."); - return EXIT_TEST_SKIP; - } + if (getuid() != 0) + return log_tests_skipped("not running as root"); r = bpf_firewall_supported(); - if (r == BPF_FIREWALL_UNSUPPORTED) { - log_notice("BPF firewalling not supported, skipping"); - return EXIT_TEST_SKIP; - } + if (r == BPF_FIREWALL_UNSUPPORTED) + return log_tests_skipped("BPF firewalling not supported"); assert_se(r > 0); if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) @@ -71,7 +63,7 @@ int main(int argc, char *argv[]) { /* The simple tests suceeded. Now let's try full unit-based use-case. */ - assert_se(manager_new(UNIT_FILE_USER, true, &m) >= 0); + assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); assert_se(u = unit_new(m, sizeof(Service))); @@ -110,9 +102,8 @@ int main(int argc, char *argv[]) { unit_dump(u, stdout, NULL); r = bpf_firewall_compile(u); - if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM )) - /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */ - return EXIT_TEST_SKIP; + if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM)) + return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)"); assert_se(r >= 0); assert(u->ip_bpf_ingress); diff --git a/src/test/test-bus-util.c b/src/test/test-bus-util.c index 791b3928fe..a536608ce0 100644 --- a/src/test/test-bus-util.c +++ b/src/test/test-bus-util.c @@ -2,38 +2,7 @@ #include "bus-util.h" #include "log.h" - -static void test_name_async(unsigned n_messages) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; - unsigned i; - - log_info("/* %s (%u) */", __func__, n_messages); - - r = bus_open_system_watch_bind_with_description(&bus, "test-bus"); - if (r < 0) { - log_error_errno(r, "Failed to connect to bus: %m"); - return; - } - - r = bus_request_name_async_may_reload_dbus(bus, NULL, "org.freedesktop.systemd.test-bus-util", 0, NULL); - if (r < 0) { - log_error_errno(r, "Failed to request name: %m"); - return; - } - - for (i = 0; i < n_messages; i++) { - r = sd_bus_process(bus, NULL); - log_debug("stage %u: sd_bus_process returned %d", i, r); - if (r < 0) { - log_notice_errno(r, "Processing failed: %m"); - return; - } - - if (r > 0 && i + 1 < n_messages) - (void) sd_bus_wait(bus, USEC_PER_SEC / 3); - } -} +#include "tests.h" static int callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { return 1; @@ -78,12 +47,8 @@ static void test_destroy_callback(void) { } int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); - test_name_async(0); - test_name_async(20); test_destroy_callback(); return 0; diff --git a/src/test/test-capability.c b/src/test/test-capability.c index af6d808b6d..dae85f2f91 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -14,13 +14,19 @@ #include "fileio.h" #include "macro.h" #include "parse-util.h" +#include "tests.h" #include "util.h" static uid_t test_uid = -1; static gid_t test_gid = -1; +#if HAS_FEATURE_ADDRESS_SANITIZER +/* Keep CAP_SYS_PTRACE when running under Address Sanitizer */ +static const uint64_t test_flags = UINT64_C(1) << CAP_SYS_PTRACE; +#else /* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */ -static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE; +static const uint64_t test_flags = UINT64_C(1) << CAP_DAC_OVERRIDE; +#endif /* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */ static void test_last_cap_file(void) { @@ -91,10 +97,9 @@ static int setup_tests(bool *run_ambient) { int r; nobody = getpwnam(NOBODY_USER_NAME); - if (!nobody) { - log_error_errno(errno, "Could not find nobody user: %m"); - return -EXIT_TEST_SKIP; - } + if (!nobody) + return log_error_errno(errno, "Could not find nobody user: %m"); + test_uid = nobody->pw_uid; test_gid = nobody->pw_gid; @@ -180,8 +185,6 @@ static void test_update_inherited_set(void) { caps = cap_get_proc(); assert_se(caps); - assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); - assert(fv == CAP_CLEAR); set = (UINT64_C(1) << CAP_CHOWN); @@ -197,12 +200,6 @@ static void test_set_ambient_caps(void) { uint64_t set = 0; cap_flag_value_t fv; - caps = cap_get_proc(); - assert_se(caps); - assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); - assert(fv == CAP_CLEAR); - cap_free(caps); - assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0); set = (UINT64_C(1) << CAP_CHOWN); @@ -218,23 +215,20 @@ static void test_set_ambient_caps(void) { } int main(int argc, char *argv[]) { - int r; bool run_ambient; + test_setup_logging(LOG_INFO); + test_last_cap_file(); test_last_cap_probe(); - log_parse_environment(); - log_open(); - log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported())); if (getuid() != 0) - return EXIT_TEST_SKIP; + return log_tests_skipped("not running as root"); - r = setup_tests(&run_ambient); - if (r < 0) - return -r; + if (setup_tests(&run_ambient) < 0) + return log_tests_skipped("setup failed"); show_capabilities(); diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index d65959edf1..7f6c0c2772 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -1,10 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 David Strauss -***/ #include <stdio.h> +#include "cgroup.h" +#include "cgroup-util.h" #include "macro.h" #include "manager.h" #include "rm-rf.h" @@ -13,26 +12,41 @@ #include "tests.h" #include "unit.h" +#define ASSERT_CGROUP_MASK(got, expected) \ + log_cgroup_mask(got, expected); \ + assert_se(got == expected) + +#define ASSERT_CGROUP_MASK_JOINED(got, expected) ASSERT_CGROUP_MASK(got, CGROUP_MASK_EXTEND_JOINED(expected)) + +static void log_cgroup_mask(CGroupMask got, CGroupMask expected) { + _cleanup_free_ char *e_store = NULL, *g_store = NULL; + + assert_se(cg_mask_to_string(expected, &e_store) >= 0); + log_info("Expected mask: %s\n", e_store); + assert_se(cg_mask_to_string(got, &g_store) >= 0); + log_info("Got mask: %s\n", g_store); +} + static int test_cgroup_mask(void) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; _cleanup_(manager_freep) Manager *m = NULL; - Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep; + Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep, *nomem_parent, *nomem_leaf; int r; + CGroupMask cpu_accounting_mask = get_cpu_accounting_mask(); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - puts("Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); /* Prepare the manager. */ - assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(set_unit_path(get_testdata_dir()) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); if (IN_SET(r, -EPERM, -EACCES)) { - puts("manager_new: Permission denied. Skipping test."); - return EXIT_TEST_SKIP; + log_error_errno(r, "manager_new: %m"); + return log_tests_skipped("cannot create manager"); } + assert_se(r >= 0); /* Turn off all kinds of default accouning, so that we can @@ -54,43 +68,55 @@ static int test_cgroup_mask(void) { assert_se(manager_load_startable_unit_or_warn(m, "daughter.service", NULL, &daughter) >= 0); assert_se(manager_load_startable_unit_or_warn(m, "grandchild.service", NULL, &grandchild) >= 0); assert_se(manager_load_startable_unit_or_warn(m, "parent-deep.slice", NULL, &parent_deep) >= 0); + assert_se(manager_load_startable_unit_or_warn(m, "nomem.slice", NULL, &nomem_parent) >= 0); + assert_se(manager_load_startable_unit_or_warn(m, "nomemleaf.service", NULL, &nomem_leaf) >= 0); assert_se(UNIT_DEREF(son->slice) == parent); assert_se(UNIT_DEREF(daughter->slice) == parent); assert_se(UNIT_DEREF(parent_deep->slice) == parent); assert_se(UNIT_DEREF(grandchild->slice) == parent_deep); + assert_se(UNIT_DEREF(nomem_leaf->slice) == nomem_parent); root = UNIT_DEREF(parent->slice); + assert_se(UNIT_DEREF(nomem_parent->slice) == root); /* Verify per-unit cgroups settings. */ - assert_se(unit_get_own_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT)); - assert_se(unit_get_own_mask(daughter) == 0); - assert_se(unit_get_own_mask(grandchild) == 0); - assert_se(unit_get_own_mask(parent_deep) == CGROUP_MASK_MEMORY); - assert_se(unit_get_own_mask(parent) == (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); - assert_se(unit_get_own_mask(root) == 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(son), CGROUP_MASK_CPU); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(daughter), cpu_accounting_mask); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(grandchild), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(parent_deep), CGROUP_MASK_MEMORY); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(nomem_parent), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); + ASSERT_CGROUP_MASK_JOINED(unit_get_own_mask(root), 0); /* Verify aggregation of member masks */ - assert_se(unit_get_members_mask(son) == 0); - assert_se(unit_get_members_mask(daughter) == 0); - assert_se(unit_get_members_mask(grandchild) == 0); - assert_se(unit_get_members_mask(parent_deep) == 0); - assert_se(unit_get_members_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(son), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(daughter), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(grandchild), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(parent_deep), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(parent), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(nomem_parent), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(nomem_leaf), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_members_mask(root), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of sibling masks. */ - assert_se(unit_get_siblings_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(daughter) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(grandchild) == 0); - assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(son), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(daughter), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(grandchild), 0); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(parent_deep), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(parent), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(nomem_parent), (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(nomem_leaf), (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); + ASSERT_CGROUP_MASK_JOINED(unit_get_siblings_mask(root), (CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of target masks. */ - assert_se(unit_get_target_mask(son) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(daughter) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(grandchild) == 0); - assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(son), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(daughter), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(grandchild), 0); + ASSERT_CGROUP_MASK(unit_get_target_mask(parent_deep), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(parent), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_parent), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(nomem_leaf), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_IO | CGROUP_MASK_BLKIO) & m->cgroup_supported)); + ASSERT_CGROUP_MASK(unit_get_target_mask(root), (CGROUP_MASK_EXTEND_JOINED(CGROUP_MASK_CPU | cpu_accounting_mask | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); return 0; } @@ -104,7 +130,7 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) { static void test_cg_mask_to_string(void) { test_cg_mask_to_string_one(0, NULL); - test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids"); + test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids bpf-firewall bpf-devices"); test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu"); test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct"); test_cg_mask_to_string_one(CGROUP_MASK_IO, "io"); @@ -120,13 +146,12 @@ static void test_cg_mask_to_string(void) { } int main(int argc, char* argv[]) { - int rc = 0; + int rc = EXIT_SUCCESS; - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); - TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); test_cg_mask_to_string(); + TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); return rc; } diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index d49356315e..a3239d73f5 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -14,6 +14,7 @@ #include "string-util.h" #include "strv.h" #include "test-helper.h" +#include "tests.h" #include "user-util.h" #include "util.h" @@ -296,7 +297,7 @@ static void test_shift_path(void) { test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo"); test_shift_path_one("/foobar/waldo", "", "/foobar/waldo"); test_shift_path_one("/foobar/waldo", "/foobar", "/waldo"); - test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo"); + test_shift_path_one("/foobar/waldo", "/hogehoge", "/foobar/waldo"); } static void test_mask_supported(void) { @@ -368,6 +369,17 @@ static void test_is_wanted(void) { "systemd.unified_cgroup_hierarchy=0 " "systemd.legacy_systemd_cgroup_controller=0", 1) >= 0); test_is_wanted_print(false); + + /* cgroup_no_v1=all implies unified cgroup hierarchy, unless otherwise + * explicitly specified. */ + assert_se(setenv("SYSTEMD_PROC_CMDLINE", + "cgroup_no_v1=all", 1) >= 0); + test_is_wanted_print(false); + + assert_se(setenv("SYSTEMD_PROC_CMDLINE", + "cgroup_no_v1=all " + "systemd.unified_cgroup_hierarchy=0", 1) >= 0); + test_is_wanted_print(false); } static void test_cg_tests(void) { @@ -447,9 +459,7 @@ static void test_cg_get_keyed_attribute(void) { } int main(void) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_path_decode_unit(); test_path_get_unit(); diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 9211c996ac..5cdfd2dc54 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -9,7 +9,7 @@ #include "string-util.h" #include "util.h" -int main(int argc, char*argv[]) { +int main(int argc, char *argv[]) { char *path; char *c, *p; diff --git a/src/test/test-chown-rec.c b/src/test/test-chown-rec.c new file mode 100644 index 0000000000..305d44f568 --- /dev/null +++ b/src/test/test-chown-rec.c @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <sys/xattr.h> + +#include "alloc-util.h" +#include "chown-recursive.h" +#include "log.h" +#include "rm-rf.h" +#include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" + +static const uint8_t acl[] = { + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x07, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00, + 0xff, 0xff, 0xff, 0xff, +}; + +static const uint8_t default_acl[] = { + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x07, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00, + 0xff, 0xff, 0xff, 0xff, +}; + +static bool has_xattr(const char *p) { + char buffer[sizeof(acl) * 4]; + + if (lgetxattr(p, "system.posix_acl_access", buffer, sizeof(buffer)) < 0) { + if (IN_SET(errno, EOPNOTSUPP, ENOTTY, ENODATA, ENOSYS)) + return false; + } + + return true; +} + +static void test_chown_recursive(void) { + _cleanup_(rm_rf_physical_and_freep) char *t = NULL; + struct stat st; + const char *p; + + umask(022); + assert_se(mkdtemp_malloc(NULL, &t) >= 0); + + p = strjoina(t, "/dir"); + assert_se(mkdir(p, 0777) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/symlink"); + assert_se(symlink("../../", p) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0777); + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/reg"); + assert_se(mknod(p, S_IFREG|0777, 0) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISREG(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/sock"); + assert_se(mknod(p, S_IFSOCK|0777, 0) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISSOCK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/fifo"); + assert_se(mknod(p, S_IFIFO|0777, 0) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISFIFO(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(!has_xattr(p)); + + /* We now apply an xattr to the dir, and check it again */ + p = strjoina(t, "/dir"); + assert_se(setxattr(p, "system.posix_acl_access", acl, sizeof(acl), 0) >= 0); + assert_se(setxattr(p, "system.posix_acl_default", default_acl, sizeof(default_acl), 0) >= 0); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0775); /* acl change changed the mode too */ + assert_se(st.st_uid == 0); + assert_se(st.st_gid == 0); + assert_se(has_xattr(p)); + + assert_se(path_chown_recursive(t, 1, 2) >= 0); + + p = strjoina(t, "/dir"); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0775); + assert_se(st.st_uid == 1); + assert_se(st.st_gid == 2); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/symlink"); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0777); + assert_se(st.st_uid == 1); + assert_se(st.st_gid == 2); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/reg"); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISREG(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 1); + assert_se(st.st_gid == 2); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/sock"); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISSOCK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 1); + assert_se(st.st_gid == 2); + assert_se(!has_xattr(p)); + + p = strjoina(t, "/dir/fifo"); + assert_se(lstat(p, &st) >= 0); + assert_se(S_ISFIFO(st.st_mode)); + assert_se((st.st_mode & 07777) == 0755); + assert_se(st.st_uid == 1); + assert_se(st.st_gid == 2); + assert_se(!has_xattr(p)); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + if (geteuid() != 0) + return log_tests_skipped("not running as root"); + + test_chown_recursive(); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-clock.c b/src/test/test-clock.c index 50e9b7756f..018e679b45 100644 --- a/src/test/test-clock.c +++ b/src/test/test-clock.c @@ -9,12 +9,13 @@ #include "clock-util.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "log.h" #include "macro.h" +#include "tmpfile-util.h" static void test_clock_is_localtime(void) { - char adjtime[] = "/tmp/test-adjtime.XXXXXX"; - int fd = -1; + _cleanup_(unlink_tempfilep) char adjtime[] = "/tmp/test-adjtime.XXXXXX"; _cleanup_fclose_ FILE* f = NULL; static const struct scenario { @@ -41,22 +42,17 @@ static void test_clock_is_localtime(void) { /* without an adjtime file we default to UTC */ assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); - fd = mkostemp_safe(adjtime); - assert_se(fd >= 0); + assert_se(fmkostemp_safe(adjtime, "w", &f) == 0); log_info("adjtime test file: %s", adjtime); - f = fdopen(fd, "w"); - assert_se(f); for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); log_info("%s", scenarios[i].contents); rewind(f); - ftruncate(fd, 0); + ftruncate(fileno(f), 0); assert_se(write_string_stream(f, scenarios[i].contents, WRITE_STRING_FILE_AVOID_NEWLINE) == 0); assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result); } - - unlink(adjtime); } /* Test with the real /etc/adjtime */ diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 7ce6ee80ea..5c2d00af88 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -26,6 +26,7 @@ #include "strv.h" #include "tomoyo-util.h" #include "user-util.h" +#include "tests.h" #include "util.h" #include "virt.h" @@ -113,7 +114,7 @@ static void test_condition_test_path(void) { condition_free(condition); } -static int test_condition_test_control_group_controller(void) { +static void test_condition_test_control_group_controller(void) { Condition *condition; CGroupMask system_mask; CGroupController controller; @@ -123,7 +124,7 @@ static int test_condition_test_control_group_controller(void) { r = cg_unified_flush(); if (r < 0) { log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m"); - return EXIT_TEST_SKIP; + return; } /* Invalid controllers are ignored */ @@ -180,8 +181,6 @@ static int test_condition_test_control_group_controller(void) { assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); - - return EXIT_SUCCESS; } static void test_condition_test_ac_power(void) { @@ -675,9 +674,7 @@ static void test_condition_test_group(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_condition_test_path(); test_condition_test_ac_power(); diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 2ec2dfc261..9fd8b6b590 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -13,9 +13,11 @@ #include "macro.h" #include "mkdir.h" #include "parse-util.h" +#include "path-util.h" #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "user-util.h" #include "util.h" @@ -42,7 +44,7 @@ static void test_conf_files_list(bool use_root) { _cleanup_strv_free_ char **found_files = NULL, **found_files2 = NULL; const char *root_dir, *search_1, *search_2, *expect_a, *expect_b, *expect_c, *mask; - log_debug("/* %s */", __func__); + log_debug("/* %s(%s) */", __func__, yes_no(use_root)); setup_test_dir(tmp_dir, "/dir1/a.conf", @@ -92,12 +94,68 @@ static void test_conf_files_list(bool use_root) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } +static void test_conf_files_insert(const char *root) { + _cleanup_strv_free_ char **s = NULL; + + log_info("/* %s root=%s */", __func__, strempty(root)); + + char **dirs = STRV_MAKE("/dir1", "/dir2", "/dir3"); + + _cleanup_free_ const char + *foo1 = prefix_root(root, "/dir1/foo.conf"), + *foo2 = prefix_root(root, "/dir2/foo.conf"), + *bar2 = prefix_root(root, "/dir2/bar.conf"), + *zzz3 = prefix_root(root, "/dir3/zzz.conf"), + *whatever = prefix_root(root, "/whatever.conf"); + + assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(foo2))); + + /* The same file again, https://github.com/systemd/systemd/issues/11124 */ + assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(foo2))); + + /* Lower priority → new entry is ignored */ + assert_se(conf_files_insert(&s, root, dirs, "/dir3/foo.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(foo2))); + + /* Higher priority → new entry replaces */ + assert_se(conf_files_insert(&s, root, dirs, "/dir1/foo.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(foo1))); + + /* Earlier basename */ + assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(bar2, foo1))); + + /* Later basename */ + assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); + + /* All lower priority → all ignored */ + assert_se(conf_files_insert(&s, root, dirs, "/dir3/zzz.conf") == 0); + assert_se(conf_files_insert(&s, root, dirs, "/dir2/bar.conf") == 0); + assert_se(conf_files_insert(&s, root, dirs, "/dir3/bar.conf") == 0); + assert_se(conf_files_insert(&s, root, dirs, "/dir2/foo.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); + + /* Two entries that don't match any of the directories, but match basename */ + assert_se(conf_files_insert(&s, root, dirs, "/dir4/zzz.conf") == 0); + assert_se(conf_files_insert(&s, root, dirs, "/zzz.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, zzz3))); + + /* An entry that doesn't match any of the directories, no match at all */ + assert_se(conf_files_insert(&s, root, dirs, "/whatever.conf") == 0); + assert_se(strv_equal(s, STRV_MAKE(bar2, foo1, whatever, zzz3))); +} + int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_conf_files_list(false); test_conf_files_list(true); + test_conf_files_insert(NULL); + test_conf_files_insert("/root"); + test_conf_files_insert("/root/"); + return 0; } diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 7335ad6666..2921338f62 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -2,12 +2,12 @@ #include "conf-parser.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "log.h" #include "macro.h" #include "string-util.h" #include "strv.h" +#include "tmpfile-util.h" #include "util.h" static void test_config_parse_path_one(const char *rvalue, const char *expected) { @@ -236,6 +236,18 @@ static const char* const config_file[] = { "3\n", "[Section]\n" + "#hogehoge\\\n" /* continuation is ignored in comment */ + "setting1=1\\\n" /* normal continuation */ + "2\\\n" + "3\n", + + "[Section]\n" + "setting1=1\\\n" /* normal continuation */ + "#hogehoge\\\n" /* commented out line in continuation is ignored */ + "2\\\n" + "3\n", + + "[Section]\n" "setting1=1\\\n" /* continuation with extra trailing backslash at the end */ "2\\\n" "3\\\n", @@ -272,9 +284,9 @@ static const char* const config_file[] = { static void test_config_parse(unsigned i, const char *s) { _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-conf-parser.XXXXXX"; - int fd, r; _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *setting1 = NULL; + int r; const ConfigTableItem items[] = { { "Section", "setting1", config_parse_string, 0, &setting1}, @@ -283,12 +295,9 @@ static void test_config_parse(unsigned i, const char *s) { log_info("== %s[%i] ==", __func__, i); - fd = mkostemp_safe(name); - assert_se(fd >= 0); - assert_se((size_t) write(fd, s, strlen(s)) == strlen(s)); - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(f = fdopen(fd, "r")); + assert_se(fmkostemp_safe(name, "r+", &f) == 0); + assert_se(fwrite(s, strlen(s), 1, f) == 1); + rewind(f); /* int config_parse(const char *unit, @@ -314,27 +323,27 @@ static void test_config_parse(unsigned i, const char *s) { assert_se(streq(setting1, "1")); break; - case 4 ... 5: + case 4 ... 7: assert_se(r == 0); assert_se(streq(setting1, "1 2 3")); break; - case 6: + case 8: assert_se(r == 0); assert_se(streq(setting1, "1\\\\ \\\\2")); break; - case 7: + case 9: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD"))); break; - case 8 ... 9: + case 10 ... 11: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD") " foobar")); break; - case 10 ... 11: + case 12 ... 13: assert_se(r == -ENOBUFS); assert_se(setting1 == NULL); break; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 2e8d251ac1..b17a1c53fe 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -14,6 +14,8 @@ #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "tests.h" +#include "tmpfile-util.h" #include "user-util.h" #include "util.h" @@ -254,7 +256,7 @@ static void test_copy_atomic(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); test_copy_file(); test_copy_file_fd(); diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index c8a83f0fc9..a4b96da045 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -7,7 +7,7 @@ #include "parse-util.h" #include "strv.h" -int main(int argc, char*argv[]) { +int main(int argc, char *argv[]) { _cleanup_strv_free_ char **l = NULL; int n, i; usec_t duration = USEC_PER_SEC / 10; diff --git a/src/test/test-date.c b/src/test/test-date.c index 99b6f2eb9e..cba51e225c 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "string-util.h" +#include "tests.h" #include "util.h" static void test_should_pass(const char *p) { @@ -66,9 +67,7 @@ static void test_one_noutc(const char *p) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_one("17:41"); test_one("18:42:44"); diff --git a/src/test/test-dev-setup.c b/src/test/test-dev-setup.c new file mode 100644 index 0000000000..9414ea6c3e --- /dev/null +++ b/src/test/test-dev-setup.c @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "capability-util.h" +#include "dev-setup.h" +#include "fs-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "tmpfile-util.h" + +int main(int argc, char *argv[]) { + _cleanup_(rm_rf_physical_and_freep) char *p = NULL; + const char *f; + struct stat st; + + if (have_effective_cap(CAP_DAC_OVERRIDE) <= 0) + return EXIT_TEST_SKIP; + + assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0); + + f = prefix_roota(p, "/run"); + assert_se(mkdir(f, 0755) >= 0); + + assert_se(make_inaccessible_nodes(p, 1, 1) >= 0); + + f = prefix_roota(p, "/run/systemd/inaccessible/reg"); + assert_se(stat(f, &st) >= 0); + assert_se(S_ISREG(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + + f = prefix_roota(p, "/run/systemd/inaccessible/dir"); + assert_se(stat(f, &st) >= 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + + f = prefix_roota(p, "/run/systemd/inaccessible/fifo"); + assert_se(stat(f, &st) >= 0); + assert_se(S_ISFIFO(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + + f = prefix_roota(p, "/run/systemd/inaccessible/sock"); + assert_se(stat(f, &st) >= 0); + assert_se(S_ISSOCK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + + f = prefix_roota(p, "/run/systemd/inaccessible/chr"); + if (stat(f, &st) < 0) + assert_se(errno == ENOENT); + else { + assert_se(S_ISCHR(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + } + + f = prefix_roota(p, "/run/systemd/inaccessible/blk"); + if (stat(f, &st) < 0) + assert_se(errno == ENOENT); + else { + assert_se(S_ISBLK(st.st_mode)); + assert_se((st.st_mode & 07777) == 0000); + } + + return EXIT_SUCCESS; +} diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 02496a121d..ad8d9ace16 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Dave Reisner -***/ #include <sys/types.h> diff --git a/src/test/test-dissect-image.c b/src/test/test-dissect-image.c index a0a909baf0..7b32e8373f 100644 --- a/src/test/test-dissect-image.c +++ b/src/test/test-dissect-image.c @@ -7,13 +7,14 @@ #include "log.h" #include "loop-util.h" #include "string-util.h" +#include "tests.h" int main(int argc, char *argv[]) { _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; int r, i; - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); if (argc < 2) { log_error("Requires one command line argument."); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index 8ed7dbd1e6..ead5311705 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -1,45 +1,70 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - ***/ #include "alloc-util.h" #include "dns-domain.h" #include "macro.h" #include "string-util.h" +#include "tests.h" -static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) { +static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret, int ret_ldh) { char buffer[buffer_sz]; int r; + const char *w = what; - r = dns_label_unescape(&what, buffer, buffer_sz); + log_info("%s, %s, %zu, →%d/%d", what, expect, buffer_sz, ret, ret_ldh); + + r = dns_label_unescape(&w, buffer, buffer_sz, 0); assert_se(r == ret); + if (r >= 0) + assert_se(streq(buffer, expect)); - if (r < 0) - return; + w = what; + r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_LDH); + assert_se(r == ret_ldh); + if (r >= 0) + assert_se(streq(buffer, expect)); - assert_se(streq(buffer, expect)); + w = what; + r = dns_label_unescape(&w, buffer, buffer_sz, DNS_LABEL_NO_ESCAPES); + const int ret_noe = strchr(what, '\\') ? -EINVAL : ret; + assert_se(r == ret_noe); + if (r >= 0) + assert_se(streq(buffer, expect)); } static void test_dns_label_unescape(void) { - test_dns_label_unescape_one("hallo", "hallo", 6, 5); - test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS); - test_dns_label_unescape_one("", "", 10, 0); - test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12); - test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5); - test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL); - test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL); - test_dns_label_unescape_one("hallo\\032 ", "hallo ", 20, 7); - test_dns_label_unescape_one(".", "", 20, 0); - test_dns_label_unescape_one("..", "", 20, -EINVAL); - test_dns_label_unescape_one(".foobar", "", 20, -EINVAL); - test_dns_label_unescape_one("foobar.", "foobar", 20, 6); - test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL); + log_info("/* %s */", __func__); + + test_dns_label_unescape_one("hallo", "hallo", 6, 5, 5); + test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS, -ENOBUFS); + test_dns_label_unescape_one("", "", 10, 0, 0); + test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12, -EINVAL); + test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5, 5); + test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_one("hallo\\032 ", "hallo ", 20, 7, -EINVAL); + test_dns_label_unescape_one(".", "", 20, 0, 0); + test_dns_label_unescape_one("..", "", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_one(".foobar", "", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_one("foobar.", "foobar", 20, 6, 6); + test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_one("foo-bar", "foo-bar", 20, 7, 7); + test_dns_label_unescape_one("foo-", "foo-", 20, 4, -EINVAL); + test_dns_label_unescape_one("-foo", "-foo", 20, 4, -EINVAL); + test_dns_label_unescape_one("-foo-", "-foo-", 20, 5, -EINVAL); + test_dns_label_unescape_one("foo-.", "foo-", 20, 4, -EINVAL); + test_dns_label_unescape_one("foo.-", "foo", 20, 3, 3); + test_dns_label_unescape_one("foo\\032", "foo ", 20, 4, -EINVAL); + test_dns_label_unescape_one("foo\\045", "foo-", 20, 4, -EINVAL); + test_dns_label_unescape_one("głąb", "głąb", 20, 6, -EINVAL); } static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) { uint8_t buffer[buffer_sz]; int r; + log_info("%s, %s, %zu, →%d", what, expect, buffer_sz, ret); + r = dns_name_to_wire_format(what, buffer, buffer_sz, false); assert_se(r == ret); @@ -81,6 +106,8 @@ static void test_dns_name_to_wire_format(void) { 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', 3, 'a', '1', '2', 0 }; + log_info("/* %s */", __func__); + test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0)); test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1)); @@ -101,6 +128,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp const char *label; int r; + log_info("%s, %s, %s, %zu, %d, %d", what, expect1, expect2, buffer_sz, ret1, ret2); + label = what + strlen(what); r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz); @@ -115,6 +144,8 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp } static void test_dns_label_unescape_suffix(void) { + log_info("/* %s */", __func__); + test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0); test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS); test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0); @@ -140,6 +171,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex _cleanup_free_ char *t = NULL; int r; + log_info("%s, %zu, %s, →%d", what, l, expect, ret); + r = dns_label_escape_new(what, l, &t); assert_se(r == ret); @@ -150,6 +183,8 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex } static void test_dns_label_escape(void) { + log_info("/* %s */", __func__); + test_dns_label_escape_one("", 0, NULL, -EINVAL); test_dns_label_escape_one("hallo", 5, "hallo", 5); test_dns_label_escape_one("hallo", 6, "hallo\\000", 9); @@ -160,7 +195,7 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in _cleanup_free_ char *t = NULL; int r; - r = dns_name_normalize(what, &t); + r = dns_name_normalize(what, 0, &t); assert_se(r == ret); if (r < 0) @@ -321,7 +356,7 @@ static void test_dns_name_reverse(void) { static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) { _cleanup_free_ char *p = NULL; - assert_se(dns_name_concat(a, b, &p) == r); + assert_se(dns_name_concat(a, b, 0, &p) == r); assert_se(streq_ptr(p, result)); } @@ -340,46 +375,68 @@ static void test_dns_name_concat(void) { test_dns_name_concat_one(NULL, "foo", 0, "foo"); } -static void test_dns_name_is_valid_one(const char *s, int ret) { +static void test_dns_name_is_valid_one(const char *s, int ret, int ret_ldh) { + log_info("%s, →%d", s, ret); + assert_se(dns_name_is_valid(s) == ret); + assert_se(dns_name_is_valid_ldh(s) == ret_ldh); } static void test_dns_name_is_valid(void) { - test_dns_name_is_valid_one("foo", 1); - test_dns_name_is_valid_one("foo.", 1); - test_dns_name_is_valid_one("foo..", 0); - test_dns_name_is_valid_one("Foo", 1); - test_dns_name_is_valid_one("foo.bar", 1); - test_dns_name_is_valid_one("foo.bar.baz", 1); - test_dns_name_is_valid_one("", 1); - test_dns_name_is_valid_one("foo..bar", 0); - test_dns_name_is_valid_one(".foo.bar", 0); - test_dns_name_is_valid_one("foo.bar.", 1); - test_dns_name_is_valid_one("foo.bar..", 0); - test_dns_name_is_valid_one("\\zbar", 0); - test_dns_name_is_valid_one("ä", 1); - test_dns_name_is_valid_one("\n", 0); + log_info("/* %s */", __func__); + + test_dns_name_is_valid_one("foo", 1, 1); + test_dns_name_is_valid_one("foo.", 1, 1); + test_dns_name_is_valid_one("foo..", 0, 0); + test_dns_name_is_valid_one("Foo", 1, 1); + test_dns_name_is_valid_one("foo.bar", 1, 1); + test_dns_name_is_valid_one("foo.bar.baz", 1, 1); + test_dns_name_is_valid_one("", 1, 1); + test_dns_name_is_valid_one("foo..bar", 0, 0); + test_dns_name_is_valid_one(".foo.bar", 0, 0); + test_dns_name_is_valid_one("foo.bar.", 1, 1); + test_dns_name_is_valid_one("foo.bar..", 0, 0); + test_dns_name_is_valid_one("\\zbar", 0, 0); + test_dns_name_is_valid_one("ä", 1, 0); + test_dns_name_is_valid_one("\n", 0, 0); + + test_dns_name_is_valid_one("dash-", 1, 0); + test_dns_name_is_valid_one("-dash", 1, 0); + test_dns_name_is_valid_one("dash-dash", 1, 1); + test_dns_name_is_valid_one("foo.dash-", 1, 0); + test_dns_name_is_valid_one("foo.-dash", 1, 0); + test_dns_name_is_valid_one("foo.dash-dash", 1, 1); + test_dns_name_is_valid_one("foo.dash-.bar", 1, 0); + test_dns_name_is_valid_one("foo.-dash.bar", 1, 0); + test_dns_name_is_valid_one("foo.dash-dash.bar", 1, 1); + test_dns_name_is_valid_one("dash-.bar", 1, 0); + test_dns_name_is_valid_one("-dash.bar", 1, 0); + test_dns_name_is_valid_one("dash-dash.bar", 1, 1); + test_dns_name_is_valid_one("-.bar", 1, 0); + test_dns_name_is_valid_one("foo.-", 1, 0); /* 256 characters */ - test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0); + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0, 0); /* 255 characters */ - test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0); + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0, 0); /* 254 characters */ - test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0); + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0, 0); /* 253 characters */ - test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1); + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1, 1); /* label of 64 chars length */ - test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0); + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0, 0); /* label of 63 chars length */ - test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1); + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1, 1); } static void test_dns_service_name_is_valid(void) { + log_info("/* %s */", __func__); + assert_se(dns_service_name_is_valid("Lennart's Compüter")); assert_se(dns_service_name_is_valid("piff.paff")); @@ -391,6 +448,7 @@ static void test_dns_service_name_is_valid(void) { } static void test_dns_srv_type_is_valid(void) { + log_info("/* %s */", __func__); assert_se(dns_srv_type_is_valid("_http._tcp")); assert_se(dns_srv_type_is_valid("_foo-bar._tcp")); @@ -414,6 +472,7 @@ static void test_dns_srv_type_is_valid(void) { } static void test_dnssd_srv_type_is_valid(void) { + log_info("/* %s */", __func__); assert_se(dnssd_srv_type_is_valid("_http._tcp")); assert_se(dnssd_srv_type_is_valid("_foo-bar._tcp")); @@ -440,6 +499,8 @@ static void test_dnssd_srv_type_is_valid(void) { static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) { _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + log_info("%s, %s, %s, →%d, %s", a, b, c, r, d); + assert_se(dns_service_join(a, b, c, &t) == r); assert_se(streq_ptr(t, d)); @@ -453,6 +514,8 @@ static void test_dns_service_join_one(const char *a, const char *b, const char * } static void test_dns_service_join(void) { + log_info("/* %s */", __func__); + test_dns_service_join_one("", "", "", -EINVAL, NULL); test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL); test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL); @@ -470,6 +533,8 @@ static void test_dns_service_join(void) { static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) { _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + log_info("%s, %s, %s, %s, →%d", joined, a, b, c, r); + assert_se(dns_service_split(joined, &x, &y, &z) == r); assert_se(streq_ptr(x, a)); assert_se(streq_ptr(y, b)); @@ -486,6 +551,8 @@ static void test_dns_service_split_one(const char *joined, const char *a, const } static void test_dns_service_split(void) { + log_info("/* %s */", __func__); + test_dns_service_split_one("", NULL, NULL, ".", 0); test_dns_service_split_one("foo", NULL, NULL, "foo", 0); test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0); @@ -498,11 +565,15 @@ static void test_dns_service_split(void) { static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) { _cleanup_free_ char *s = NULL; + log_info("%s, %s, %s, →%s", name, old_suffix, new_suffix, result); + assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r); assert_se(streq_ptr(s, result)); } static void test_dns_name_change_suffix(void) { + log_info("/* %s */", __func__); + test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo"); test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff"); test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff"); @@ -517,11 +588,15 @@ static void test_dns_name_change_suffix(void) { static void test_dns_name_suffix_one(const char *name, unsigned n_labels, const char *result, int ret) { const char *p = NULL; + log_info("%s, %d, →%s, %d", name, n_labels, result, ret); + assert_se(ret == dns_name_suffix(name, n_labels, &p)); assert_se(streq_ptr(p, result)); } static void test_dns_name_suffix(void) { + log_info("/* %s */", __func__); + test_dns_name_suffix_one("foo.bar", 2, "foo.bar", 0); test_dns_name_suffix_one("foo.bar", 1, "bar", 1); test_dns_name_suffix_one("foo.bar", 0, "", 2); @@ -539,10 +614,14 @@ static void test_dns_name_suffix(void) { } static void test_dns_name_count_labels_one(const char *name, int n) { + log_info("%s, →%d", name, n); + assert_se(dns_name_count_labels(name) == n); } static void test_dns_name_count_labels(void) { + log_info("/* %s */", __func__); + test_dns_name_count_labels_one("foo.bar.quux.", 3); test_dns_name_count_labels_one("foo.bar.quux", 3); test_dns_name_count_labels_one("foo.bar.", 2); @@ -555,10 +634,14 @@ static void test_dns_name_count_labels(void) { } static void test_dns_name_equal_skip_one(const char *a, unsigned n_labels, const char *b, int ret) { + log_info("%s, %u, %s, →%d", a, n_labels, b, ret); + assert_se(dns_name_equal_skip(a, n_labels, b) == ret); } static void test_dns_name_equal_skip(void) { + log_info("/* %s */", __func__); + test_dns_name_equal_skip_one("foo", 0, "bar", 0); test_dns_name_equal_skip_one("foo", 0, "foo", 1); test_dns_name_equal_skip_one("foo", 1, "foo", 0); @@ -586,6 +669,8 @@ static void test_dns_name_equal_skip(void) { } static void test_dns_name_compare_func(void) { + log_info("/* %s */", __func__); + assert_se(dns_name_compare_func("", "") == 0); assert_se(dns_name_compare_func("", ".") == 0); assert_se(dns_name_compare_func(".", "") == 0); @@ -601,11 +686,15 @@ static void test_dns_name_compare_func(void) { static void test_dns_name_common_suffix_one(const char *a, const char *b, const char *result) { const char *c; + log_info("%s, %s, →%s", a, b, result); + assert_se(dns_name_common_suffix(a, b, &c) >= 0); assert_se(streq(c, result)); } static void test_dns_name_common_suffix(void) { + log_info("/* %s */", __func__); + test_dns_name_common_suffix_one("", "", ""); test_dns_name_common_suffix_one("foo", "", ""); test_dns_name_common_suffix_one("", "foo", ""); @@ -640,6 +729,7 @@ static void test_dns_name_apply_idna(void) { #else const int ret = 0; #endif + log_info("/* %s */", __func__); /* IDNA2008 forbids names with hyphens in third and fourth positions * (https://tools.ietf.org/html/rfc5891#section-4.2.3.1). @@ -677,6 +767,8 @@ static void test_dns_name_apply_idna(void) { } static void test_dns_name_is_valid_or_address(void) { + log_info("/* %s */", __func__); + assert_se(dns_name_is_valid_or_address(NULL) == 0); assert_se(dns_name_is_valid_or_address("") == 0); assert_se(dns_name_is_valid_or_address("foobar") > 0); @@ -689,9 +781,7 @@ static void test_dns_name_is_valid_or_address(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_dns_label_unescape(); test_dns_label_unescape_suffix(); diff --git a/src/test/test-emergency-action.c b/src/test/test-emergency-action.c new file mode 100644 index 0000000000..8ce28ed9f5 --- /dev/null +++ b/src/test/test-emergency-action.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "emergency-action.h" +#include "tests.h" + +static void test_parse_emergency_action(void) { + EmergencyAction x; + + log_info("/* %s */", __func__); + + assert_se(parse_emergency_action("none", false, &x) == 0); + assert_se(x == EMERGENCY_ACTION_NONE); + assert_se(parse_emergency_action("reboot", false, &x) == -EOPNOTSUPP); + assert_se(parse_emergency_action("reboot-force", false, &x) == -EOPNOTSUPP); + assert_se(parse_emergency_action("reboot-immediate", false, &x) == -EOPNOTSUPP); + assert_se(parse_emergency_action("poweroff", false, &x) == -EOPNOTSUPP); + assert_se(parse_emergency_action("poweroff-force", false, &x) == -EOPNOTSUPP); + assert_se(parse_emergency_action("poweroff-immediate", false, &x) == -EOPNOTSUPP); + assert_se(x == EMERGENCY_ACTION_NONE); + assert_se(parse_emergency_action("exit", false, &x) == 0); + assert_se(x == EMERGENCY_ACTION_EXIT); + assert_se(parse_emergency_action("exit-force", false, &x) == 0); + assert_se(x == EMERGENCY_ACTION_EXIT_FORCE); + assert_se(parse_emergency_action("exit-forcee", false, &x) == -EINVAL); + + assert_se(parse_emergency_action("none", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_NONE); + assert_se(parse_emergency_action("reboot", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_REBOOT); + assert_se(parse_emergency_action("reboot-force", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_REBOOT_FORCE); + assert_se(parse_emergency_action("reboot-immediate", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_REBOOT_IMMEDIATE); + assert_se(parse_emergency_action("poweroff", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_POWEROFF); + assert_se(parse_emergency_action("poweroff-force", true, &x) == 0); + assert_se(x == EMERGENCY_ACTION_POWEROFF_FORCE); + assert_se(parse_emergency_action("poweroff-immediate", true, &x) == 0); + assert_se(parse_emergency_action("exit", true, &x) == 0); + assert_se(parse_emergency_action("exit-force", true, &x) == 0); + assert_se(parse_emergency_action("exit-forcee", true, &x) == -EINVAL); + assert_se(x == EMERGENCY_ACTION_EXIT_FORCE); +} + +int main(int argc, char **argv) { + test_setup_logging(LOG_INFO); + + test_parse_emergency_action(); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-engine.c b/src/test/test-engine.c index d072a15cb1..0673d36b62 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -18,24 +18,18 @@ int main(int argc, char *argv[]) { Job *j; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); /* prepare the test */ - assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(set_unit_path(get_testdata_dir()) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return EXIT_TEST_SKIP; - } + if (MANAGER_SKIP_TEST(r)) + return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index e645d4968e..f57a26021c 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -5,6 +5,8 @@ #include "env-util.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "serialize.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -12,13 +14,13 @@ static void test_strv_env_delete(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; - a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF"); assert_se(a); - b = strv_new("PIEP", "FOO", NULL); + b = strv_new("PIEP", "FOO"); assert_se(b); - c = strv_new("SCHLUMPF", NULL); + c = strv_new("SCHLUMPF"); assert_se(c); d = strv_env_delete(a, 2, b, c); @@ -42,7 +44,7 @@ static void test_strv_env_get(void) { static void test_strv_env_unset(void) { _cleanup_strv_free_ char **l = NULL; - l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES"); assert_se(l); assert_se(strv_env_unset(l, "SCHLUMPF") == l); @@ -55,7 +57,7 @@ static void test_strv_env_unset(void) { static void test_strv_env_set(void) { _cleanup_strv_free_ char **l = NULL, **r = NULL; - l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES"); assert_se(l); r = strv_env_set(l, "WALDO=WALDO"); @@ -71,10 +73,10 @@ static void test_strv_env_set(void) { static void test_strv_env_merge(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL; - a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF"); assert_se(a); - b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES"); assert_se(b); r = strv_env_merge(2, a, b); @@ -247,8 +249,7 @@ static void test_env_clean(void) { "xyz\n=xyz", "xyz=xyz\n", "another=one", - "another=final one", - NULL); + "another=final one"); assert_se(e); assert_se(!strv_env_is_valid(e)); assert_se(strv_env_clean(e) == e); @@ -303,61 +304,6 @@ static void test_env_assignment_is_valid(void) { assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\"")); } -static void test_deserialize_environment(void) { - _cleanup_strv_free_ char **env = strv_new("A=1", NULL); - - assert_se(deserialize_environment(&env, "env=B=2") >= 0); - assert_se(deserialize_environment(&env, "env=FOO%%=a\\177b\\nc\\td e") >= 0); - - assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e"))); - - assert_se(deserialize_environment(&env, "env=foo\\") < 0); - assert_se(deserialize_environment(&env, "env=bar\\_baz") < 0); -} - -static void test_serialize_environment(void) { - char fn[] = "/tmp/test-env-util.XXXXXXX"; - int fd, r; - _cleanup_fclose_ FILE *f = NULL; - - _cleanup_strv_free_ char **env = strv_new("A=1", - "B=2", - "C=ąęółń", - "D=D=a\\x0Ab", - "FOO%%=a\177b\nc\td e", - NULL); - _cleanup_strv_free_ char **env2 = NULL; - - fd = mkostemp_safe(fn); - assert_se(fd >= 0); - - assert_se(f = fdopen(fd, "r+")); - - assert_se(serialize_environment(f, env) == 0); - assert_se(fflush_and_check(f) == 0); - - rewind(f); - - for (;;) { - char line[LINE_MAX]; - const char *l; - - if (!fgets(line, sizeof line, f)) - break; - - char_array_0(line); - l = strstrip(line); - - r = deserialize_environment(&env2, l); - assert_se(r == 1); - } - assert_se(feof(f)); - - assert_se(strv_equal(env, env2)); - - unlink(fn); -} - int main(int argc, char *argv[]) { test_strv_env_delete(); test_strv_env_get(); @@ -374,8 +320,6 @@ int main(int argc, char *argv[]) { test_env_name_is_valid(); test_env_value_is_valid(); test_env_assignment_is_valid(); - test_deserialize_environment(); - test_serialize_environment(); return 0; } diff --git a/src/test/test-escape.c b/src/test/test-escape.c index 650a9a058d..4ee4aa974d 100644 --- a/src/test/test-escape.c +++ b/src/test/test-escape.c @@ -3,6 +3,7 @@ #include "alloc-util.h" #include "escape.h" #include "macro.h" +#include "tests.h" static void test_cescape(void) { _cleanup_free_ char *escaped; @@ -119,9 +120,7 @@ static void test_shell_maybe_quote(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_cescape(); test_cunescape(); diff --git a/src/test/test-exec-util.c b/src/test/test-exec-util.c index cfc8b5f88e..21a4538d74 100644 --- a/src/test/test-exec-util.c +++ b/src/test/test-exec-util.c @@ -16,9 +16,11 @@ #include "fs-util.h" #include "log.h" #include "macro.h" +#include "path-util.h" #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "tests.h" static int here = 0, here2 = 0, here3 = 0; void *ignore_stdout_args[] = {&here, &here2, &here3}; @@ -115,9 +117,9 @@ static void test_execute_directory(bool gather_stdout) { assert_se(chmod(mask2e, 0755) == 0); if (gather_stdout) - execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL); + execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL); else - execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL); + execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL); assert_se(chdir(template_lo) == 0); assert_se(access("it_works", F_OK) >= 0); @@ -182,7 +184,7 @@ static void test_execution_order(void) { assert_se(chmod(override, 0755) == 0); assert_se(chmod(masked, 0755) == 0); - execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL); + execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL); assert_se(read_full_file(output, &contents, NULL) >= 0); assert_se(streq(contents, "30-override\n80-foo\n90-bar\nlast\n")); @@ -264,7 +266,7 @@ static void test_stdout_gathering(void) { assert_se(chmod(name2, 0755) == 0); assert_se(chmod(name3, 0755) == 0); - r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL); + r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL); assert_se(r >= 0); log_info("got: %s", output); @@ -275,7 +277,7 @@ static void test_stdout_gathering(void) { static void test_environment_gathering(void) { char template[] = "/tmp/test-exec-util.XXXXXXX", **p; const char *dirs[] = {template, NULL}; - const char *name, *name2, *name3; + const char *name, *name2, *name3, *old; int r; char **tmp = NULL; /* this is only used in the forked process, no cleanup here */ @@ -321,7 +323,33 @@ static void test_environment_gathering(void) { assert_se(chmod(name2, 0755) == 0); assert_se(chmod(name3, 0755) == 0); - r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL); + /* When booting in containers or without initramfs there might not be + * any PATH in the environ and if there is no PATH /bin/sh built-in + * PATH may leak and override systemd's DEFAULT_PATH which is not + * good. Force our own PATH in environment, to prevent expansion of sh + * built-in $PATH */ + old = getenv("PATH"); + r = setenv("PATH", "no-sh-built-in-path", 1); + assert_se(r >= 0); + + r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL); + assert_se(r >= 0); + + STRV_FOREACH(p, env) + log_info("got env: \"%s\"", *p); + + assert_se(streq(strv_env_get(env, "A"), "22:23:24")); + assert_se(streq(strv_env_get(env, "B"), "12")); + assert_se(streq(strv_env_get(env, "C"), "001")); + assert_se(streq(strv_env_get(env, "PATH"), "no-sh-built-in-path:/no/such/file")); + + /* now retest with "default" path passed in, as created by + * manager_default_environment */ + env = strv_free(env); + env = strv_new("PATH=" DEFAULT_PATH); + assert_se(env); + + r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, env); assert_se(r >= 0); STRV_FOREACH(p, env) @@ -330,13 +358,14 @@ static void test_environment_gathering(void) { assert_se(streq(strv_env_get(env, "A"), "22:23:24")); assert_se(streq(strv_env_get(env, "B"), "12")); assert_se(streq(strv_env_get(env, "C"), "001")); - assert_se(endswith(strv_env_get(env, "PATH"), ":/no/such/file")); + assert_se(streq(strv_env_get(env, "PATH"), DEFAULT_PATH ":/no/such/file")); + + /* reset environ PATH */ + (void) setenv("PATH", old, 1); } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_execute_directory(true); test_execute_directory(false); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index fa8efdddd2..2115061add 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -28,6 +28,8 @@ #include "util.h" #include "virt.h" +static bool can_unshare; + typedef void (*test_function_t)(Manager *m); static void check(Manager *m, Unit *unit, int status_expected, int code_expected) { @@ -52,6 +54,9 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected n = now(CLOCK_MONOTONIC); if (ts + timeout < n) { log_error("Test timeout when testing %s", unit->id); + r = unit_kill(unit, KILL_ALL, SIGKILL, NULL); + if (r < 0) + log_error_errno(r, "Failed to kill %s: %m", unit->id); exit(EXIT_FAILURE); } } @@ -105,6 +110,25 @@ invalid: return false; } +static bool check_user_has_group_with_same_name(const char *name) { + struct passwd *p; + struct group *g; + + assert(name); + + p = getpwnam(name); + if (!p || + !streq(p->pw_name, name)) + return false; + + g = getgrgid(p->pw_gid); + if (!g || + !streq(g->gr_name, name)) + return false; + + return true; +} + static bool is_inaccessible_available(void) { char *p; @@ -129,7 +153,7 @@ static void test(Manager *m, const char *unit_name, int status_expected, int cod assert_se(unit_name); assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); check(m, unit, status_expected, code_expected); } @@ -137,7 +161,7 @@ static void test_exec_bindpaths(Manager *m) { assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0); assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0); - test(m, "exec-bindpaths.service", 0, CLD_EXITED); + test(m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); (void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL); @@ -208,7 +232,7 @@ static void test_exec_ignoresigpipe(Manager *m) { static void test_exec_privatetmp(Manager *m) { assert_se(touch("/tmp/test-exec_privatetmp") >= 0); - test(m, "exec-privatetmp-yes.service", 0, CLD_EXITED); + test(m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-privatetmp-no.service", 0, CLD_EXITED); unlink("/tmp/test-exec_privatetmp"); @@ -226,9 +250,9 @@ static void test_exec_privatedevices(Manager *m) { return; } - test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED); + test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-privatedevices-no.service", 0, CLD_EXITED); - test(m, "exec-privatedevices-disabled-by-prefix.service", 0, CLD_EXITED); + test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); /* We use capsh to test if the capabilities are * properly set, so be sure that it exists */ @@ -264,21 +288,21 @@ static void test_exec_protectkernelmodules(Manager *m) { test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED); test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED); - test(m, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED); + test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); } static void test_exec_readonlypaths(Manager *m) { - test(m, "exec-readonlypaths-simple.service", 0, CLD_EXITED); + test(m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); if (path_is_read_only_fs("/var") > 0) { log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__); return; } - test(m, "exec-readonlypaths.service", 0, CLD_EXITED); - test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED); - test(m, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED); + test(m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); + test(m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); } static void test_exec_readwritepaths(Manager *m) { @@ -288,7 +312,7 @@ static void test_exec_readwritepaths(Manager *m) { return; } - test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED); + test(m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); } static void test_exec_inaccessiblepaths(Manager *m) { @@ -298,26 +322,28 @@ static void test_exec_inaccessiblepaths(Manager *m) { return; } - test(m, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED); + test(m, "exec-inaccessiblepaths-proc.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); if (path_is_read_only_fs("/") > 0) { log_notice("Root directory is readonly, skipping remaining tests in %s", __func__); return; } - test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED); + test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); } static void test_exec_temporaryfilesystem(Manager *m) { - test(m, "exec-temporaryfilesystem-options.service", 0, CLD_EXITED); - test(m, "exec-temporaryfilesystem-ro.service", 0, CLD_EXITED); - test(m, "exec-temporaryfilesystem-rw.service", 0, CLD_EXITED); - test(m, "exec-temporaryfilesystem-usr.service", 0, CLD_EXITED); + test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); } static void test_exec_systemcallfilter(Manager *m) { #if HAVE_SECCOMP + int r; + if (!is_seccomp_available()) { log_notice("Seccomp not available, skipping %s", __func__); return; @@ -327,18 +353,34 @@ static void test_exec_systemcallfilter(Manager *m) { test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED); test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED); test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED); + + r = find_binary("python3", NULL); + if (r < 0) { + log_notice_errno(r, "Skipping remaining tests in %s, could not find python3 binary: %m", __func__); + return; + } + test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED); test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED); + test(m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED); #endif } static void test_exec_systemcallerrornumber(Manager *m) { #if HAVE_SECCOMP + int r; + if (!is_seccomp_available()) { log_notice("Seccomp not available, skipping %s", __func__); return; } + r = find_binary("python3", NULL); + if (r < 0) { + log_notice_errno(r, "Skipping %s, could not find python3 binary: %m", __func__); + return; + } + test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED); test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED); #endif @@ -351,13 +393,13 @@ static void test_exec_restrictnamespaces(Manager *m) { return; } - test(m, "exec-restrictnamespaces-no.service", 0, CLD_EXITED); + test(m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED); - test(m, "exec-restrictnamespaces-mnt.service", 0, CLD_EXITED); + test(m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); test(m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED); - test(m, "exec-restrictnamespaces-merge-and.service", 0, CLD_EXITED); - test(m, "exec-restrictnamespaces-merge-or.service", 0, CLD_EXITED); - test(m, "exec-restrictnamespaces-merge-all.service", 0, CLD_EXITED); + test(m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); + test(m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); + test(m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); #endif } @@ -426,10 +468,15 @@ static void test_exec_supplementarygroups(Manager *m) { } static void test_exec_dynamicuser(Manager *m) { - test(m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED); - test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED); - test(m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED); - test(m, "exec-dynamicuser-statedir.service", 0, CLD_EXITED); + + test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + if (check_user_has_group_with_same_name("adm")) + test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + if (check_user_has_group_with_same_name("games")) + test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); + test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL); @@ -437,7 +484,7 @@ static void test_exec_dynamicuser(Manager *m) { (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL); test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED); - test(m, "exec-dynamicuser-statedir-migrate-step2.service", 0, CLD_EXITED); + test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL); @@ -595,19 +642,29 @@ static void test_exec_privatenetwork(Manager *m) { return; } - test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED); + test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED); } static void test_exec_oomscoreadjust(Manager *m) { test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED); + + if (detect_container() > 0) { + log_notice("Testing in container, skipping remaining tests in %s", __func__); + return; + } test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED); } static void test_exec_ioschedulingclass(Manager *m) { test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED); test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED); - test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED); test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED); + + if (detect_container() > 0) { + log_notice("Testing in container, skipping remaining tests in %s", __func__); + return; + } + test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED); } static void test_exec_unsetenvironment(Manager *m) { @@ -625,6 +682,14 @@ static void test_exec_standardinput(Manager *m) { test(m, "exec-standardinput-file.service", 0, CLD_EXITED); } +static void test_exec_standardoutput(Manager *m) { + test(m, "exec-standardoutput-file.service", 0, CLD_EXITED); +} + +static void test_exec_standardoutput_append(Manager *m) { + test(m, "exec-standardoutput-append.service", 0, CLD_EXITED); +} + static int run_tests(UnitFileScope scope, const test_function_t *tests) { const test_function_t *test = NULL; _cleanup_(manager_freep) Manager *m = NULL; @@ -633,10 +698,8 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) { assert_se(tests); r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return EXIT_TEST_SKIP; - } + if (MANAGER_SKIP_TEST(r)) + return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); @@ -648,6 +711,8 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) { int main(int argc, char *argv[]) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + _cleanup_free_ char *test_execute_path = NULL; + _cleanup_hashmap_free_ Hashmap *s = NULL; static const test_function_t user_tests[] = { test_exec_basic, test_exec_ambientcapabilities, @@ -672,6 +737,8 @@ int main(int argc, char *argv[]) { test_exec_restrictnamespaces, test_exec_runtimedirectory, test_exec_standardinput, + test_exec_standardoutput, + test_exec_standardoutput_append, test_exec_supplementarygroups, test_exec_systemcallerrornumber, test_exec_systemcallfilter, @@ -690,28 +757,32 @@ int main(int argc, char *argv[]) { }; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); + +#if HAS_FEATURE_ADDRESS_SANITIZER + if (is_run_on_travis_ci()) { + log_notice("Running on TravisCI under ASan, skipping, see https://github.com/systemd/systemd/issues/10696"); + return EXIT_TEST_SKIP; + } +#endif (void) unsetenv("USER"); (void) unsetenv("LOGNAME"); (void) unsetenv("SHELL"); + can_unshare = have_namespaces(); + /* It is needed otherwise cgroup creation fails */ - if (getuid() != 0) { - puts("Skipping test: not root"); - return EXIT_TEST_SKIP; - } + if (getuid() != 0) + return log_tests_skipped("not root"); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - puts("Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(set_unit_path(get_testdata_dir("/test-execute")) >= 0); + test_execute_path = path_join(get_testdata_dir(), "test-execute"); + assert_se(set_unit_path(test_execute_path) >= 0); /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test * cases, otherwise (and if they are present in the environment), @@ -727,5 +798,33 @@ int main(int argc, char *argv[]) { if (r != 0) return r; + r = run_tests(UNIT_FILE_SYSTEM, system_tests); + if (r != 0) + return r; + +#if HAVE_SECCOMP + /* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */ + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping unshare() filtered tests."); + return 0; + } + + assert_se(s = hashmap_new(NULL)); + r = seccomp_syscall_resolve_name("unshare"); + assert_se(r != __NR_SCMP_ERROR); + assert_se(hashmap_put(s, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0); + assert_se(unshare(CLONE_NEWNS) < 0); + assert_se(errno == EOPNOTSUPP); + + can_unshare = false; + + r = run_tests(UNIT_FILE_USER, user_tests); + if (r != 0) + return r; + return run_tests(UNIT_FILE_SYSTEM, system_tests); +#else + return 0; +#endif } diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index a04403d748..7a0a2ad7d8 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -10,7 +10,10 @@ #include "path-util.h" #include "process-util.h" #include "random-util.h" +#include "serialize.h" #include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" #include "util.h" static void test_close_many(void) { @@ -316,7 +319,7 @@ static void test_read_nr_open(void) { int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); test_close_many(); test_close_nointr(); diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c index 7d68a6b966..fb9d397569 100644 --- a/src/test/test-fdset.c +++ b/src/test/test-fdset.c @@ -5,8 +5,8 @@ #include "fd-util.h" #include "fdset.h" -#include "fileio.h" #include "macro.h" +#include "tmpfile-util.h" #include "util.h" static void test_fdset_new_fill(void) { diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 14ba075144..bf918c1d1e 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -6,7 +6,7 @@ #include "alloc-util.h" #include "ctype.h" -#include "def.h" +#include "env-file.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" @@ -16,30 +16,23 @@ #include "process-util.h" #include "string-util.h" #include "strv.h" +#include "tests.h" +#include "tmpfile-util.h" #include "util.h" static void test_parse_env_file(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-in-XXXXXX", p[] = "/tmp/test-fileio-out-XXXXXX"; - int fd, r; FILE *f; _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL, *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL; _cleanup_strv_free_ char **a = NULL, **b = NULL; char **i; unsigned k; + int r; - fd = mkostemp_safe(p); - assert_se(fd >= 0); - close(fd); - - fd = mkostemp_safe(t); - assert_se(fd >= 0); - - f = fdopen(fd, "w"); - assert_se(f); - + assert_se(fmkostemp_safe(t, "w", &f) == 0); fputs("one=BAR \n" "# comment\n" " # comment \n" @@ -63,7 +56,7 @@ static void test_parse_env_file(void) { fflush(f); fclose(f); - r = load_env_file(NULL, t, NULL, &a); + r = load_env_file(NULL, t, &a); assert_se(r >= 0); STRV_FOREACH(i, a) @@ -90,7 +83,7 @@ static void test_parse_env_file(void) { } r = parse_env_file( - NULL, t, NULL, + NULL, t, "one", &one, "two", &two, "three", &three, @@ -100,8 +93,7 @@ static void test_parse_env_file(void) { "seven", &seven, "eight", &eight, "export nine", &nine, - "ten", &ten, - NULL); + "ten", &ten); assert_se(r >= 0); @@ -127,10 +119,16 @@ static void test_parse_env_file(void) { assert_se(streq(nine, "nineval")); assert_se(ten == NULL); + { + /* prepare a temporary file to write the environment to */ + _cleanup_close_ int fd = mkostemp_safe(p); + assert_se(fd >= 0); + } + r = write_env_file(p, a); assert_se(r >= 0); - r = load_env_file(NULL, p, NULL, &b); + r = load_env_file(NULL, p, &b); assert_se(r >= 0); } @@ -138,21 +136,12 @@ static void test_parse_multiline_env_file(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-in-XXXXXX", p[] = "/tmp/test-fileio-out-XXXXXX"; - int fd, r; FILE *f; _cleanup_strv_free_ char **a = NULL, **b = NULL; char **i; + int r; - fd = mkostemp_safe(p); - assert_se(fd >= 0); - close(fd); - - fd = mkostemp_safe(t); - assert_se(fd >= 0); - - f = fdopen(fd, "w"); - assert_se(f); - + assert_se(fmkostemp_safe(t, "w", &f) == 0); fputs("one=BAR\\\n" " VAR\\\n" "\tGAR\n" @@ -168,7 +157,7 @@ static void test_parse_multiline_env_file(void) { fflush(f); fclose(f); - r = load_env_file(NULL, t, NULL, &a); + r = load_env_file(NULL, t, &a); assert_se(r >= 0); STRV_FOREACH(i, a) @@ -179,28 +168,28 @@ static void test_parse_multiline_env_file(void) { assert_se(streq_ptr(a[2], "tri=bar var \tgar ")); assert_se(a[3] == NULL); + { + _cleanup_close_ int fd = mkostemp_safe(p); + assert_se(fd >= 0); + } + r = write_env_file(p, a); assert_se(r >= 0); - r = load_env_file(NULL, p, NULL, &b); + r = load_env_file(NULL, p, &b); assert_se(r >= 0); } static void test_merge_env_file(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX"; - int fd, r; _cleanup_fclose_ FILE *f = NULL; _cleanup_strv_free_ char **a = NULL; char **i; + int r; - fd = mkostemp_safe(t); - assert_se(fd >= 0); - + assert_se(fmkostemp_safe(t, "w", &f) == 0); log_info("/* %s (%s) */", __func__, t); - f = fdopen(fd, "w"); - assert_se(f); - r = write_string_stream(f, "one=1 \n" "twelve=${one}2\n" @@ -257,19 +246,14 @@ static void test_merge_env_file(void) { static void test_merge_env_file_invalid(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX"; - int fd, r; _cleanup_fclose_ FILE *f = NULL; _cleanup_strv_free_ char **a = NULL; char **i; + int r; - fd = mkostemp_safe(t); - assert_se(fd >= 0); - + assert_se(fmkostemp_safe(t, "w", &f) == 0); log_info("/* %s (%s) */", __func__, t); - f = fdopen(fd, "w"); - assert_se(f); - r = write_string_stream(f, "unset one \n" "unset one= \n" @@ -296,16 +280,11 @@ static void test_merge_env_file_invalid(void) { static void test_executable_is_script(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX"; - int fd, r; _cleanup_fclose_ FILE *f = NULL; char *command; + int r; - fd = mkostemp_safe(t); - assert_se(fd >= 0); - - f = fdopen(fd, "w"); - assert_se(f); - + assert_se(fmkostemp_safe(t, "w", &f) == 0); fputs("#! /bin/script -a -b \ngoo goo", f); fflush(f); @@ -488,7 +467,7 @@ static void test_load_env_file_pairs(void) { f = fdopen(fd, "r"); assert_se(f); - r = load_env_file_pairs(f, fn, NULL, &l); + r = load_env_file_pairs(f, fn, &l); assert_se(r >= 0); assert_se(strv_length(l) == 14); @@ -631,8 +610,43 @@ static void test_tempfn(void) { free(ret); } +static const char chars[] = + "Aąę„”\n루\377"; + +static void test_fgetc(void) { + _cleanup_fclose_ FILE *f = NULL; + char c; + + f = fmemopen((void*) chars, sizeof(chars), "re"); + assert_se(f); + + for (unsigned i = 0; i < sizeof(chars); i++) { + assert_se(safe_fgetc(f, &c) == 1); + assert_se(c == chars[i]); + + /* EOF is -1, and hence we can't push value 255 in this way */ + assert_se(ungetc(c, f) != EOF || c == EOF); + assert_se(c == EOF || safe_fgetc(f, &c) == 1); + assert_se(c == chars[i]); + + /* But it works when we push it properly cast */ + assert_se(ungetc((unsigned char) c, f) != EOF); + assert_se(safe_fgetc(f, &c) == 1); + assert_se(c == chars[i]); + } + + assert_se(safe_fgetc(f, &c) == 0); +} + static const char buffer[] = "Some test data\n" + "루Non-ascii chars: ąę„”\n" + "terminators\r\n" + "and even more\n\r" + "now the same with a NUL\n\0" + "and more\r\0" + "and even more\r\n\0" + "and yet even more\n\r\0" "With newlines, and a NUL byte\0" "\n" "an empty line\n" @@ -645,6 +659,27 @@ static void test_read_line_one_file(FILE *f) { assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data")); line = mfree(line); + assert_se(read_line(f, (size_t) -1, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 13 && streq(line, "terminators")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "and even more")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 25 && streq(line, "now the same with a NUL")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 10 && streq(line, "and more")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 16 && streq(line, "and even more")); + line = mfree(line); + + assert_se(read_line(f, (size_t) -1, &line) == 20 && streq(line, "and yet even more")); + line = mfree(line); + assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte")); line = mfree(line); @@ -661,10 +696,7 @@ static void test_read_line_one_file(FILE *f) { /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first * character after the previous limit. Let's make use of tha to continue our test. */ - assert_se(read_line(f, 1024, &line) == 61 && streq(line, "line that is supposed to be truncated, because it is so long")); - line = mfree(line); - - assert_se(read_line(f, 1024, &line) == 1 && streq(line, "")); + assert_se(read_line(f, 1024, &line) == 62 && streq(line, "line that is supposed to be truncated, because it is so long")); line = mfree(line); assert_se(read_line(f, 1024, &line) == 0 && streq(line, "")); @@ -709,10 +741,77 @@ static void test_read_line3(void) { assert_se(read_line(f, LINE_MAX, NULL) == 0); } +static void test_read_line4(void) { + static const struct { + size_t length; + const char *string; + } eof_endings[] = { + /* Each of these will be followed by EOF and should generate the one same single string */ + { 3, "foo" }, + { 4, "foo\n" }, + { 4, "foo\r" }, + { 4, "foo\0" }, + { 5, "foo\n\0" }, + { 5, "foo\r\0" }, + { 5, "foo\r\n" }, + { 5, "foo\n\r" }, + { 6, "foo\r\n\0" }, + { 6, "foo\n\r\0" }, + }; + + size_t i; + int r; + + for (i = 0; i < ELEMENTSOF(eof_endings); i++) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *s = NULL; + + assert_se(f = fmemopen((void*) eof_endings[i].string, eof_endings[i].length, "r")); + + r = read_line(f, (size_t) -1, &s); + assert_se((size_t) r == eof_endings[i].length); + assert_se(streq_ptr(s, "foo")); + + assert_se(read_line(f, (size_t) -1, NULL) == 0); /* Ensure we hit EOF */ + } +} + +static void test_read_nul_string(void) { + static const char test[] = "string nr. 1\0" + "string nr. 2\n\0" + "\377empty string follows\0" + "\0" + "final string\n is empty\0" + "\0"; + + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *s = NULL; + + assert_se(f = fmemopen((void*) test, sizeof(test)-1, "r")); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 13 && streq_ptr(s, "string nr. 1")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 14 && streq_ptr(s, "string nr. 2\n")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 22 && streq_ptr(s, "\377empty string follows")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, "")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 23 && streq_ptr(s, "final string\n is empty")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, "")); + s = mfree(s); + + assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 0 && streq_ptr(s, "")); +} + int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_parse_env_file(); test_parse_multiline_env_file(); @@ -730,9 +829,12 @@ int main(int argc, char *argv[]) { test_search_and_fopen_nulstr(); test_writing_tmpfile(); test_tempfn(); + test_fgetc(); test_read_line(); test_read_line2(); test_read_line3(); + test_read_line4(); + test_read_nul_string(); return 0; } diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index 1b62590b49..1788e8d1ca 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -2,12 +2,13 @@ #include "firewall-util.h" #include "log.h" +#include "tests.h" #define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} int main(int argc, char *argv[]) { int r; - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0); if (r < 0) diff --git a/src/test/test-format-table.c b/src/test/test-format-table.c index adcc414161..5bede5c75b 100644 --- a/src/test/test-format-table.c +++ b/src/test/test-format-table.c @@ -5,6 +5,30 @@ #include "string-util.h" #include "time-util.h" +static void test_issue_9549(void) { + _cleanup_(table_unrefp) Table *table = NULL; + _cleanup_free_ char *formatted = NULL; + + assert_se(table = table_new("name", "type", "ro", "usage", "created", "modified")); + assert_se(table_set_align_percent(table, TABLE_HEADER_CELL(3), 100) >= 0); + assert_se(table_add_many(table, + TABLE_STRING, "foooo", + TABLE_STRING, "raw", + TABLE_BOOLEAN, false, + TABLE_SIZE, (uint64_t) (673.7*1024*1024), + TABLE_STRING, "Wed 2018-07-11 00:10:33 JST", + TABLE_STRING, "Wed 2018-07-11 00:16:00 JST") >= 0); + + table_set_width(table, 75); + assert_se(table_format(table, &formatted) >= 0); + + printf("%s\n", formatted); + assert_se(streq(formatted, + "NAME TYPE RO USAGE CREATED MODIFIED \n" + "foooo raw no 673.6M Wed 2018-07-11 00:10:33 J… Wed 2018-07-11 00:16:00 JST\n" + )); +} + int main(int argc, char *argv[]) { _cleanup_(table_unrefp) Table *t = NULL; @@ -12,7 +36,7 @@ int main(int argc, char *argv[]) { assert_se(setenv("COLUMNS", "40", 1) >= 0); - assert_se(t = table_new("ONE", "TWO", "THREE")); + assert_se(t = table_new("one", "two", "three")); assert_se(table_set_align_percent(t, TABLE_HEADER_CELL(2), 100) >= 0); @@ -135,5 +159,7 @@ int main(int argc, char *argv[]) { " yes xxx yes xxx xxx \n" "5min 5min \n")); + test_issue_9549(); + return 0; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index fc650b513e..b3a4b1749c 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -4,8 +4,6 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "id128-util.h" #include "macro.h" @@ -15,22 +13,35 @@ #include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "tests.h" +#include "tmpfile-util.h" #include "user-util.h" #include "util.h" +#include "virt.h" + +static const char *arg_test_dir = NULL; static void test_chase_symlinks(void) { _cleanup_free_ char *result = NULL; - char temp[] = "/tmp/test-chase.XXXXXX"; + char *temp; const char *top, *p, *pslash, *q, *qslash; + struct stat st; int r, pfd; + log_info("/* %s */", __func__); + + temp = strjoina(arg_test_dir ?: "/tmp", "/test-chase.XXXXXX"); assert_se(mkdtemp(temp)); top = strjoina(temp, "/top"); assert_se(mkdir(top, 0700) >= 0); p = strjoina(top, "/dot"); - assert_se(symlink(".", p) >= 0); + if (symlink(".", p) < 0) { + assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)); + log_tests_skipped_errno(errno, "symlink() not possible"); + goto cleanup; + }; p = strjoina(top, "/dotdot"); assert_se(symlink("..", p) >= 0); @@ -237,11 +248,11 @@ static void test_chase_symlinks(void) { assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0); assert_se(chown(q, 0, 0) >= 0); - assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM); + assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK); assert_se(rmdir(q) >= 0); assert_se(symlink("/etc/passwd", q) >= 0); - assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM); + assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK); assert_se(chown(p, 0, 0) >= 0); assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0); @@ -266,6 +277,30 @@ static void test_chase_symlinks(void) { assert_se(sd_id128_equal(a, b)); } + /* Test CHASE_NOFOLLOW */ + + p = strjoina(temp, "/target"); + q = strjoina(temp, "/symlink"); + assert_se(symlink(p, q) >= 0); + pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result); + assert_se(pfd > 0); + assert_se(path_equal(result, q)); + assert_se(fstat(pfd, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + result = mfree(result); + + /* s1 -> s2 -> nonexistent */ + q = strjoina(temp, "/s1"); + assert_se(symlink("s2", q) >= 0); + p = strjoina(temp, "/s2"); + assert_se(symlink("nonexistent", p) >= 0); + pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result); + assert_se(pfd > 0); + assert_se(path_equal(result, q)); + assert_se(fstat(pfd, &st) >= 0); + assert_se(S_ISLNK(st.st_mode)); + result = mfree(result); + /* Test CHASE_ONE */ p = strjoina(temp, "/start"); @@ -309,13 +344,17 @@ static void test_chase_symlinks(void) { assert_se(streq("/usr", result)); result = mfree(result); + cleanup: assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } static void test_unlink_noerrno(void) { - char name[] = "/tmp/test-close_nointr.XXXXXX"; + char *name; int fd; + log_info("/* %s */", __func__); + + name = strjoina(arg_test_dir ?: "/tmp", "/test-close_nointr.XXXXXX"); fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(close_nointr(fd) >= 0); @@ -331,32 +370,37 @@ static void test_unlink_noerrno(void) { } static void test_readlink_and_make_absolute(void) { - char tempdir[] = "/tmp/test-readlink_and_make_absolute"; - char name[] = "/tmp/test-readlink_and_make_absolute/original"; - char name2[] = "test-readlink_and_make_absolute/original"; - char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; - char *r = NULL; - _cleanup_free_ char *pwd = NULL; + const char *tempdir, *name, *name2, *name_alias; + _cleanup_free_ char *r1 = NULL, *r2 = NULL, *pwd = NULL; + + log_info("/* %s */", __func__); + + tempdir = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute"); + name = strjoina(tempdir, "/original"); + name2 = "test-readlink_and_make_absolute/original"; + name_alias = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute-alias"); assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), MKDIR_WARN_MODE) >= 0); assert_se(touch(name) >= 0); - assert_se(symlink(name, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); + if (symlink(name, name_alias) < 0) { + assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)); + log_tests_skipped_errno(errno, "symlink() not possible"); + } else { + assert_se(readlink_and_make_absolute(name_alias, &r1) >= 0); + assert_se(streq(r1, name)); + assert_se(unlink(name_alias) >= 0); - assert_se(safe_getcwd(&pwd) >= 0); + assert_se(safe_getcwd(&pwd) >= 0); - assert_se(chdir(tempdir) >= 0); - assert_se(symlink(name2, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); + assert_se(chdir(tempdir) >= 0); + assert_se(symlink(name2, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r2) >= 0); + assert_se(streq(r2, name)); + assert_se(unlink(name_alias) >= 0); - assert_se(chdir(pwd) >= 0); + assert_se(chdir(pwd) >= 0); + } assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } @@ -364,7 +408,7 @@ static void test_readlink_and_make_absolute(void) { static void test_get_files_in_directory(void) { _cleanup_strv_free_ char **l = NULL, **t = NULL; - assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(arg_test_dir ?: "/tmp", &l) >= 0); assert_se(get_files_in_directory(".", &t) >= 0); assert_se(get_files_in_directory(".", NULL) >= 0); } @@ -373,6 +417,8 @@ static void test_var_tmp(void) { _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL; const char *tmp_dir = NULL, *t; + log_info("/* %s */", __func__); + t = getenv("TMPDIR"); if (t) { tmpdir_backup = strdup(t); @@ -427,6 +473,8 @@ static void test_var_tmp(void) { } static void test_dot_or_dot_dot(void) { + log_info("/* %s */", __func__); + assert_se(!dot_or_dot_dot(NULL)); assert_se(!dot_or_dot_dot("")); assert_se(!dot_or_dot_dot("xxx")); @@ -439,8 +487,12 @@ static void test_dot_or_dot_dot(void) { static void test_access_fd(void) { _cleanup_(rmdir_and_freep) char *p = NULL; _cleanup_close_ int fd = -1; + const char *a; + + log_info("/* %s */", __func__); - assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0); + a = strjoina(arg_test_dir ?: "/tmp", "/access-fd.XXXXXX"); + assert_se(mkdtemp_malloc(a, &p) >= 0); fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC); assert_se(fd >= 0); @@ -468,16 +520,26 @@ static void test_touch_file(void) { struct stat st; const char *a; usec_t test_mtime; + int r; + + log_info("/* %s */", __func__); test_uid = geteuid() == 0 ? 65534 : getuid(); test_gid = geteuid() == 0 ? 65534 : getgid(); test_mtime = usec_sub_unsigned(now(CLOCK_REALTIME), USEC_PER_WEEK); - assert_se(mkdtemp_malloc("/dev/shm/touch-file-XXXXXX", &p) >= 0); + a = strjoina(arg_test_dir ?: "/dev/shm", "/touch-file-XXXXXX"); + assert_se(mkdtemp_malloc(a, &p) >= 0); a = strjoina(p, "/regular"); - assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0); + r = touch_file(a, false, test_mtime, test_uid, test_gid, 0640); + if (r < 0) { + assert_se(IN_SET(r, -EINVAL, -ENOSYS, -ENOTTY, -EPERM)); + log_tests_skipped_errno(errno, "touch_file() not possible"); + return; + } + assert_se(lstat(a, &st) >= 0); assert_se(st.st_uid == test_uid); assert_se(st.st_gid == test_gid); @@ -517,7 +579,12 @@ static void test_touch_file(void) { if (geteuid() == 0) { a = strjoina(p, "/cdev"); - assert_se(mknod(a, 0775 | S_IFCHR, makedev(0, 0)) >= 0); + r = mknod(a, 0775 | S_IFCHR, makedev(0, 0)); + if (r < 0 && errno == EPERM && detect_container() > 0) { + log_notice("Running in unprivileged container? Skipping remaining tests in %s", __func__); + return; + } + assert_se(r >= 0); assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0); assert_se(lstat(a, &st) >= 0); assert_se(st.st_uid == test_uid); @@ -553,7 +620,9 @@ static void test_unlinkat_deallocate(void) { _cleanup_close_ int fd = -1; struct stat st; - assert_se(tempfn_random_child(NULL, "unlink-deallocation", &p) >= 0); + log_info("/* %s */", __func__); + + assert_se(tempfn_random_child(arg_test_dir, "unlink-deallocation", &p) >= 0); fd = open(p, O_WRONLY|O_CLOEXEC|O_CREAT|O_EXCL, 0600); assert_se(fd >= 0); @@ -568,7 +637,8 @@ static void test_unlinkat_deallocate(void) { assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0); assert_se(fstat(fd, &st) >= 0); - assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6 (it worked) or 0 (we had to resort to truncation) */ + assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6 + (it worked) or 0 (we had to resort to truncation) */ assert_se(st.st_blocks == 0); assert_se(st.st_nlink == 0); } @@ -576,13 +646,87 @@ static void test_unlinkat_deallocate(void) { static void test_fsync_directory_of_file(void) { _cleanup_close_ int fd = -1; - fd = open_tmpfile_unlinkable(NULL, O_RDWR); + log_info("/* %s */", __func__); + + fd = open_tmpfile_unlinkable(arg_test_dir, O_RDWR); assert_se(fd >= 0); assert_se(fsync_directory_of_file(fd) >= 0); } +static void test_rename_noreplace(void) { + static const char* const table[] = { + "/reg", + "/dir", + "/fifo", + "/socket", + "/symlink", + NULL + }; + + _cleanup_(rm_rf_physical_and_freep) char *z = NULL; + const char *j = NULL; + char **a, **b; + + log_info("/* %s */", __func__); + + if (arg_test_dir) + j = strjoina(arg_test_dir, "/testXXXXXX"); + assert_se(mkdtemp_malloc(j, &z) >= 0); + + j = strjoina(z, table[0]); + assert_se(touch(j) >= 0); + + j = strjoina(z, table[1]); + assert_se(mkdir(j, 0777) >= 0); + + j = strjoina(z, table[2]); + (void) mkfifo(j, 0777); + + j = strjoina(z, table[3]); + (void) mknod(j, S_IFSOCK | 0777, 0); + + j = strjoina(z, table[4]); + (void) symlink("foobar", j); + + STRV_FOREACH(a, (char**) table) { + _cleanup_free_ char *x = NULL, *y = NULL; + + x = strjoin(z, *a); + assert_se(x); + + if (access(x, F_OK) < 0) { + assert_se(errno == ENOENT); + continue; + } + + STRV_FOREACH(b, (char**) table) { + _cleanup_free_ char *w = NULL; + + w = strjoin(w, *b); + assert_se(w); + + if (access(w, F_OK) < 0) { + assert_se(errno == ENOENT); + continue; + } + + assert_se(rename_noreplace(AT_FDCWD, w, AT_FDCWD, y) == -EEXIST); + } + + y = strjoin(z, "/somethingelse"); + assert_se(y); + + assert_se(rename_noreplace(AT_FDCWD, x, AT_FDCWD, y) >= 0); + assert_se(rename_noreplace(AT_FDCWD, y, AT_FDCWD, x) >= 0); + } +} + int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + arg_test_dir = argv[1]; + test_unlink_noerrno(); test_get_files_in_directory(); test_readlink_and_make_absolute(); @@ -593,6 +737,7 @@ int main(int argc, char *argv[]) { test_touch_file(); test_unlinkat_deallocate(); test_fsync_directory_of_file(); + test_rename_noreplace(); return 0; } diff --git a/src/test/test-glob-util.c b/src/test/test-glob-util.c index d78d6223c0..b4f41445fe 100644 --- a/src/test/test-glob-util.c +++ b/src/test/test-glob-util.c @@ -7,11 +7,11 @@ #include "alloc-util.h" #include "dirent-util.h" -#include "fileio.h" #include "fs-util.h" #include "glob-util.h" #include "macro.h" #include "rm-rf.h" +#include "tmpfile-util.h" static void test_glob_exists(void) { char name[] = "/tmp/test-glob_exists.XXXXXX"; diff --git a/src/test/test-hash.c b/src/test/test-hash.c index f5bc131846..44d1044bf3 100644 --- a/src/test/test-hash.c +++ b/src/test/test-hash.c @@ -7,23 +7,22 @@ #include "log.h" #include "string-util.h" #include "khash.h" +#include "tests.h" int main(int argc, char *argv[]) { _cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL; _cleanup_free_ char *s = NULL; int r; - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); assert_se(khash_new(&h, NULL) == -EINVAL); assert_se(khash_new(&h, "") == -EINVAL); r = khash_supported(); assert_se(r >= 0); - if (r == 0) { - puts("khash not supported on this kernel, skipping"); - return EXIT_TEST_SKIP; - } + if (r == 0) + return log_tests_skipped("khash not supported on this kernel"); assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP); /* undefined hash function */ diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index b695d4ee35..5376aa84c4 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -1,25 +1,21 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Daniel Buch -***/ #include "alloc-util.h" -#include "env-util.h" #include "hashmap.h" #include "log.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "util.h" -static bool arg_slow = false; - void test_hashmap_funcs(void); static void test_hashmap_replace(void) { Hashmap *m; char *val1, *val2, *val3, *val4, *val5, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -59,7 +55,7 @@ static void test_hashmap_copy(void) { Hashmap *m, *copy; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -97,7 +93,7 @@ static void test_hashmap_get_strv(void) { char **strv; char *val1, *val2, *val3, *val4; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -135,7 +131,7 @@ static void test_hashmap_move_one(void) { Hashmap *m, *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -176,7 +172,7 @@ static void test_hashmap_move(void) { Hashmap *m, *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -220,7 +216,7 @@ static void test_hashmap_update(void) { Hashmap *m; char *val1, *val2, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); val1 = strdup("old_value"); @@ -252,7 +248,7 @@ static void test_hashmap_put(void) { void *val2 = (void*) "val 2"; _cleanup_free_ char* key1 = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0); assert_se(m); @@ -272,7 +268,7 @@ static void test_hashmap_remove(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; char *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove(NULL, "key 1"); assert_se(r == NULL); @@ -302,7 +298,7 @@ static void test_hashmap_remove2(void) { char val2[] = "val 2"; void *r, *r2; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove2(NULL, "key 1", &r2); assert_se(r == NULL); @@ -334,7 +330,7 @@ static void test_hashmap_remove_value(void) { char val1[] = "val 1"; char val2[] = "val 2"; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove_value(NULL, "key 1", val1); assert_se(r == NULL); @@ -368,7 +364,7 @@ static void test_hashmap_remove_and_put(void) { int valid; char *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -404,7 +400,7 @@ static void test_hashmap_remove_and_replace(void) { void *r; int i, j; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&trivial_hash_ops); assert_se(m); @@ -457,7 +453,7 @@ static void test_hashmap_ensure_allocated(void) { Hashmap *m; int valid_hashmap; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -480,7 +476,7 @@ static void test_hashmap_foreach_key(void) { "key 3\0" "key 4\0"; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -512,7 +508,7 @@ static void test_hashmap_foreach(void) { char *val1, *val2, *val3, *val4, *s; unsigned count; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val1"); assert_se(val1); @@ -564,7 +560,7 @@ static void test_hashmap_merge(void) { Hashmap *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val1"); assert_se(val1); @@ -599,7 +595,7 @@ static void test_hashmap_contains(void) { Hashmap *m; char *val1; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -621,7 +617,7 @@ static void test_hashmap_isempty(void) { Hashmap *m; char *val1; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -640,7 +636,7 @@ static void test_hashmap_size(void) { Hashmap *m; char *val1, *val2, *val3, *val4; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -672,7 +668,7 @@ static void test_hashmap_get(void) { char *r; char *val; - log_info("%s", __func__); + log_info("/* %s */", __func__); val = strdup("my val"); assert_se(val); @@ -701,7 +697,7 @@ static void test_hashmap_get2(void) { char key_orig[] = "Key 1"; void *key_copy; - log_info("%s", __func__); + log_info("/* %s */", __func__); val = strdup("my val"); assert_se(val); @@ -742,17 +738,22 @@ static void test_hashmap_many(void) { Hashmap *h; unsigned i, j; void *v, *k; + bool slow = slow_tests_enabled(); const struct { + const char *title; const struct hash_ops *ops; unsigned n_entries; } tests[] = { - { .ops = NULL, .n_entries = arg_slow ? 1 << 20 : 240 }, - { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 }, + { "trivial_hashmap_ops", NULL, slow ? 1 << 20 : 240 }, + { "crippled_hashmap_ops", &crippled_hashmap_ops, slow ? 1 << 14 : 140 }, }; - log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast"); + log_info("/* %s (%s) */", __func__, slow ? "slow" : "fast"); for (j = 0; j < ELEMENTSOF(tests); j++) { + usec_t ts = now(CLOCK_MONOTONIC), n; + char b[FORMAT_TIMESPAN_MAX]; + assert_se(h = hashmap_new(tests[j].ops)); for (i = 1; i < tests[j].n_entries*3; i+=3) { @@ -763,7 +764,8 @@ static void test_hashmap_many(void) { for (i = 1; i < tests[j].n_entries*3; i++) assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1)); - log_info("%u <= %u * 0.8 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8); + log_info("%s %u <= %u * 0.8 = %g", + tests[j].title, hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8); assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8); assert_se(hashmap_size(h) == tests[j].n_entries); @@ -775,13 +777,63 @@ static void test_hashmap_many(void) { } hashmap_free(h); + + n = now(CLOCK_MONOTONIC); + log_info("test took %s", format_timespan(b, sizeof b, n - ts, 0)); + } +} + +extern unsigned custom_counter; +extern const struct hash_ops boring_hash_ops, custom_hash_ops; + +static void test_hashmap_free(void) { + Hashmap *h; + bool slow = slow_tests_enabled(); + usec_t ts, n; + char b[FORMAT_TIMESPAN_MAX]; + unsigned n_entries = slow ? 1 << 20 : 240; + + const struct { + const char *title; + const struct hash_ops *ops; + unsigned expect_counter; + } tests[] = { + { "string_hash_ops", &boring_hash_ops, 2 * n_entries}, + { "custom_free_hash_ops", &custom_hash_ops, 0 }, + }; + + log_info("/* %s (%s, %u entries) */", __func__, slow ? "slow" : "fast", n_entries); + + for (unsigned j = 0; j < ELEMENTSOF(tests); j++) { + ts = now(CLOCK_MONOTONIC); + assert_se(h = hashmap_new(tests[j].ops)); + + custom_counter = 0; + for (unsigned i = 0; i < n_entries; i++) { + char s[DECIMAL_STR_MAX(unsigned)]; + char *k, *v; + + xsprintf(s, "%u", i); + assert_se(k = strdup(s)); + assert_se(v = strdup(s)); + custom_counter += 2; + + assert_se(hashmap_put(h, k, v) >= 0); + } + + hashmap_free(h); + + n = now(CLOCK_MONOTONIC); + log_info("%s test took %s", tests[j].title, format_timespan(b, sizeof b, n - ts, 0)); + + assert_se(custom_counter == tests[j].expect_counter); } } static void test_hashmap_first(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -800,7 +852,7 @@ static void test_hashmap_first(void) { static void test_hashmap_first_key(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -819,7 +871,7 @@ static void test_hashmap_first_key(void) { static void test_hashmap_steal_first_key(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -836,7 +888,7 @@ static void test_hashmap_steal_first(void) { int seen[3] = {}; char *val; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -856,7 +908,7 @@ static void test_hashmap_steal_first(void) { static void test_hashmap_clear_free_free(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -867,12 +919,49 @@ static void test_hashmap_clear_free_free(void) { hashmap_clear_free_free(m); assert_se(hashmap_isempty(m)); + + assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1); + assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1); + assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1); + + hashmap_clear_free_free(m); + assert_se(hashmap_isempty(m)); +} + +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key, char, string_hash_func, string_compare_func, free); +DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full, char, string_hash_func, string_compare_func, free, char, free); + +static void test_hashmap_clear_free_with_destructor(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + + log_info("/* %s */", __func__); + + m = hashmap_new(&test_hash_ops_key); + assert_se(m); + + assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1); + assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1); + assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1); + + hashmap_clear_free(m); + assert_se(hashmap_isempty(m)); + m = hashmap_free(m); + + m = hashmap_new(&test_hash_ops_full); + assert_se(m); + + assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1); + assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1); + assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1); + + hashmap_clear_free(m); + assert_se(hashmap_isempty(m)); } static void test_hashmap_reserve(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -889,14 +978,9 @@ static void test_hashmap_reserve(void) { } void test_hashmap_funcs(void) { - int r; - log_parse_environment(); log_open(); - r = getenv_bool("SYSTEMD_SLOW_TESTS"); - arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT; - test_hashmap_copy(); test_hashmap_get_strv(); test_hashmap_move_one(); @@ -919,10 +1003,12 @@ void test_hashmap_funcs(void) { test_hashmap_get2(); test_hashmap_size(); test_hashmap_many(); + test_hashmap_free(); test_hashmap_first(); test_hashmap_first_key(); test_hashmap_steal_first_key(); test_hashmap_steal_first(); test_hashmap_clear_free_free(); + test_hashmap_clear_free_with_destructor(); test_hashmap_reserve(); } diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c index b319fa6ba9..ee4c0e66db 100644 --- a/src/test/test-hashmap.c +++ b/src/test/test-hashmap.c @@ -1,11 +1,17 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Daniel Buch -***/ #include "hashmap.h" #include "util.h" +unsigned custom_counter = 0; +static void custom_destruct(void* p) { + custom_counter--; + free(p); +} + +DEFINE_HASH_OPS_FULL(boring_hash_ops, char, string_hash_func, string_compare_func, free, char, free); +DEFINE_HASH_OPS_FULL(custom_hash_ops, char, string_hash_func, string_compare_func, custom_destruct, char, custom_destruct); + void test_hashmap_funcs(void); void test_ordered_hashmap_funcs(void); @@ -13,6 +19,8 @@ static void test_ordered_hashmap_next(void) { _cleanup_ordered_hashmap_free_ OrderedHashmap *m = NULL; int i; + log_info("/* %s */", __func__); + assert_se(m = ordered_hashmap_new(NULL)); for (i = -2; i <= 2; i++) assert_se(ordered_hashmap_put(m, INT_TO_PTR(i), INT_TO_PTR(i+10)) == 1); @@ -35,6 +43,8 @@ static void test_hashmap_free_with_destructor(void) { struct Item items[4] = {}; unsigned i; + log_info("/* %s */", __func__); + assert_se(m = hashmap_new(NULL)); for (i = 0; i < ELEMENTSOF(items) - 1; i++) assert_se(hashmap_put(m, INT_TO_PTR(i), items + i) == 1); @@ -90,6 +100,8 @@ static void test_iterated_cache(void) { Hashmap *m; IteratedCache *c; + log_info("/* %s */", __func__); + assert_se(m = hashmap_new(NULL)); assert_se(c = hashmap_iterated_cache_new(m)); compare_cache(m, c); @@ -125,6 +137,8 @@ static void test_iterated_cache(void) { static void test_path_hashmap(void) { _cleanup_hashmap_free_ Hashmap *h = NULL; + log_info("/* %s */", __func__); + assert_se(h = hashmap_new(&path_hash_ops)); assert_se(hashmap_put(h, "foo", INT_TO_PTR(1)) >= 0); diff --git a/src/test/test-helper.c b/src/test/test-helper.c index 9cf9972380..5b79d12f07 100644 --- a/src/test/test-helper.c +++ b/src/test/test-helper.c @@ -4,6 +4,7 @@ #include "random-util.h" #include "alloc-util.h" #include "cgroup-util.h" +#include "string-util.h" int enter_cgroup_subroot(void) { _cleanup_free_ char *cgroup_root = NULL, *cgroup_subroot = NULL; @@ -27,3 +28,8 @@ int enter_cgroup_subroot(void) { return cg_attach_everywhere(supported, cgroup_subroot, 0, NULL, NULL); } + +/* https://docs.travis-ci.com/user/environment-variables#default-environment-variables */ +bool is_run_on_travis_ci(void) { + return streq_ptr(getenv("TRAVIS"), "true"); +} diff --git a/src/test/test-helper.h b/src/test/test-helper.h index 3e8ccd9049..77af40d555 100644 --- a/src/test/test-helper.h +++ b/src/test/test-helper.h @@ -27,3 +27,5 @@ ) int enter_cgroup_subroot(void); + +bool is_run_on_travis_ci(void); diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c index da9f3008bb..6e9b94b933 100644 --- a/src/test/test-hexdecoct.c +++ b/src/test/test-hexdecoct.c @@ -84,7 +84,7 @@ static void test_unhexmem_one(const char *s, size_t l, int retval) { l = strlen(s); assert_se(hex = hexmem(mem, len)); - answer = strndupa(s, l); + answer = strndupa(strempty(s), l); assert_se(streq(delete_chars(answer, WHITESPACE), hex)); } } diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index 194a640eee..4126a24ceb 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -4,6 +4,7 @@ #include "fileio.h" #include "hostname-util.h" #include "string-util.h" +#include "tmpfile-util.h" #include "util.h" static void test_hostname_is_valid(void) { @@ -52,6 +53,12 @@ static void test_hostname_cleanup(void) { assert_se(streq(hostname_cleanup(s), "foobar.com")); s = strdupa("foobar.com."); assert_se(streq(hostname_cleanup(s), "foobar.com")); + s = strdupa("foo-bar.-com-."); + assert_se(streq(hostname_cleanup(s), "foo-bar.com")); + s = strdupa("foo-bar-.-com-."); + assert_se(streq(hostname_cleanup(s), "foo-bar--com")); + s = strdupa("--foo-bar.-com"); + assert_se(streq(hostname_cleanup(s), "foo-bar.com")); s = strdupa("fooBAR"); assert_se(streq(hostname_cleanup(s), "fooBAR")); s = strdupa("fooBAR.com"); @@ -78,6 +85,8 @@ static void test_hostname_cleanup(void) { assert_se(streq(hostname_cleanup(s), "foo.bar")); s = strdupa("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); + s = strdupa("xxxx........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); } static void test_read_etc_hostname(void) { diff --git a/src/test/test-id128.c b/src/test/test-id128.c index e3d07a69f3..ec50e057a3 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -7,10 +7,10 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" #include "id128-util.h" #include "macro.h" #include "string-util.h" +#include "tmpfile-util.h" #include "util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 5b6e87bf5a..75c3e305c3 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -4,12 +4,12 @@ #include "in-addr-util.h" -static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen) { +static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen, bool use_default) { union in_addr_union q; unsigned char l; int r; - r = in_addr_prefix_from_string(p, family, &q, &l); + r = in_addr_prefix_from_string_internal(p, use_default, family, &q, &l); assert_se(r == ret); if (r >= 0) { @@ -18,7 +18,7 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, assert_se(in_addr_equal(family, &q, u)); assert_se(l == prefixlen); - r = in_addr_prefix_from_string_auto(p, &f, &q, &l); + r = in_addr_prefix_from_string_auto_internal(p, use_default, &f, &q, &l); assert_se(r >= 0); assert_se(f == family); @@ -28,31 +28,57 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, } int main(int argc, char *argv[]) { - test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); - test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0); - test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1); - test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2); - test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); - test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0); - - test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); - test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1); - test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2); - test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32); - test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33); - test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64); - test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0); + test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); + test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, false); + test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, false); + test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, false); + test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); + test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, false); + + test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, false); + test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); + test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, false); + test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, false); + test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, false); + test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, false); + test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, false); + test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, false); + test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); + test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, false); + test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, false); + + test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 8, true); + test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, true); + test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, true); + test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, true); + test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, true); + test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, true); + + test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, true); + test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, true); + test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, true); + test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, true); + test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, true); + test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, true); + test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, true); + test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, true); + test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, true); + test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, true); return 0; } diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 15dd3c6966..73ea68f372 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -7,6 +7,7 @@ #include "rm-rf.h" #include "special.h" #include "string-util.h" +#include "tests.h" static void test_basic_mask_and_enable(const char *root) { const char *p; @@ -14,7 +15,7 @@ static void test_basic_mask_and_enable(const char *root) { UnitFileChange *changes = NULL; size_t n_changes = 0; - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); @@ -861,7 +862,7 @@ static void test_with_dropin(const char *root) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 1); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); assert_se(changes[0].type == UNIT_FILE_SYMLINK); @@ -983,6 +984,63 @@ static void test_with_dropin_template(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); } +static void test_preset_multiple_instances(const char *root) { + UnitFileChange *changes = NULL; + size_t n_changes = 0; + const char *p; + UnitFileState state; + + /* Set up template service files and preset file */ + p = strjoina(root, "/usr/lib/systemd/system/foo@.service"); + assert_se(write_string_file(p, + "[Install]\n" + "DefaultInstance=def\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, + "enable foo@.service bar0 bar1 bartest\n" + "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */ + "disable *\n" , WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + /* Preset a single instantiated unit specified in the list */ + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/foo@bar0.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/foo@bar0.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */ + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes > 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bartest.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + unit_file_changes_free(changes, n_changes); +} + int main(int argc, char *argv[]) { char root[] = "/tmp/rootXXXXXX"; const char *p; @@ -1012,6 +1070,7 @@ int main(int argc, char *argv[]) { test_indirect(root); test_preset_and_list(root); test_preset_order(root); + test_preset_multiple_instances(root); test_revert(root); test_static_instance(root); test_with_dropin(root); diff --git a/src/test/test-install.c b/src/test/test-install.c index 7dfc7e4272..62daaccd62 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -4,6 +4,7 @@ #include <string.h> #include "install.h" +#include "tests.h" static void dump_changes(UnitFileChange *c, unsigned n) { unsigned i; @@ -29,8 +30,7 @@ int main(int argc, char* argv[]) { size_t n_changes = 0; UnitFileState state = 0; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); h = hashmap_new(&string_hash_ops); r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); diff --git a/src/test/test-ip-protocol-list.c b/src/test/test-ip-protocol-list.c new file mode 100644 index 0000000000..79390e5289 --- /dev/null +++ b/src/test/test-ip-protocol-list.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <netinet/in.h> + +#include "macro.h" +#include "ip-protocol-list.h" +#include "stdio-util.h" +#include "string-util.h" + +static void test_int(int i) { + char str[DECIMAL_STR_MAX(int)]; + + assert_se(ip_protocol_from_name(ip_protocol_to_name(i)) == i); + + xsprintf(str, "%i", i); + assert_se(ip_protocol_from_name(ip_protocol_to_name(parse_ip_protocol(str))) == i); +} + +static void test_int_fail(int i) { + char str[DECIMAL_STR_MAX(int)]; + + assert_se(!ip_protocol_to_name(i)); + + xsprintf(str, "%i", i); + assert_se(parse_ip_protocol(str) == -EINVAL); +} + +static void test_str(const char *s) { + assert_se(streq(ip_protocol_to_name(ip_protocol_from_name(s)), s)); + assert_se(streq(ip_protocol_to_name(parse_ip_protocol(s)), s)); +} + +static void test_str_fail(const char *s) { + assert_se(ip_protocol_from_name(s) == -EINVAL); + assert_se(parse_ip_protocol(s) == -EINVAL); +} + +static void test_parse_ip_protocol(const char *s, int expected) { + assert_se(parse_ip_protocol(s) == expected); +} + +int main(int argc, const char *argv[]) { + test_int(IPPROTO_TCP); + test_int(IPPROTO_DCCP); + test_int_fail(-1); + test_int_fail(1024 * 1024); + + test_str("sctp"); + test_str("udp"); + test_str_fail("hoge"); + test_str_fail("-1"); + test_str_fail("1000000000"); + + test_parse_ip_protocol("sctp", IPPROTO_SCTP); + test_parse_ip_protocol("ScTp", IPPROTO_SCTP); + test_parse_ip_protocol("ip", IPPROTO_IP); + test_parse_ip_protocol("", IPPROTO_IP); + test_parse_ip_protocol("1", 1); + test_parse_ip_protocol("0", 0); + test_parse_ip_protocol("-10", -EINVAL); + test_parse_ip_protocol("100000000", -EINVAL); + + return 0; +} diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 106c29951e..4b658a0bdb 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -2,6 +2,7 @@ #include "clean-ipc.h" #include "user-util.h" +#include "tests.h" #include "util.h" int main(int argc, char *argv[]) { @@ -9,11 +10,14 @@ int main(int argc, char *argv[]) { int r; const char* name = argv[1] ?: NOBODY_USER_NAME; - r = get_user_creds(&name, &uid, NULL, NULL, NULL); + test_setup_logging(LOG_INFO); + + r = get_user_creds(&name, &uid, NULL, NULL, NULL, 0); + if (r == -ESRCH) + return log_tests_skipped("Failed to resolve user"); if (r < 0) { - log_full_errno(r == -ESRCH ? LOG_NOTICE : LOG_ERR, - r, "Failed to resolve \"%s\": %m", name); - return r == -ESRCH ? EXIT_TEST_SKIP : EXIT_FAILURE; + log_error_errno(r, "Failed to resolve \"%s\": %m", name); + return EXIT_FAILURE; } r = clean_ipc_by_uid(uid); diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c index dc5f9eae83..d51e0d94fd 100644 --- a/src/test/test-job-type.c +++ b/src/test/test-job-type.c @@ -6,7 +6,7 @@ #include "service.h" #include "unit.h" -int main(int argc, char*argv[]) { +int main(int argc, char *argv[]) { JobType a, b, c, ab, bc, ab_c, bc_a, a_bc; const ServiceState test_states[] = { SERVICE_DEAD, SERVICE_RUNNING }; unsigned i; diff --git a/src/test/test-journal-importer.c b/src/test/test-journal-importer.c index 56bf6a1296..cddbfa7022 100644 --- a/src/test/test-journal-importer.c +++ b/src/test/test-journal-importer.c @@ -4,8 +4,10 @@ #include <sys/stat.h> #include <fcntl.h> +#include "alloc-util.h" #include "log.h" #include "journal-importer.h" +#include "path-util.h" #include "string-util.h" #include "tests.h" @@ -20,9 +22,11 @@ static void assert_iovec_entry(const struct iovec *iovec, const char* content) { static void test_basic_parsing(void) { _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + _cleanup_free_ char *journal_data_path = NULL; int r; - imp.fd = open(get_testdata_dir("/journal-data/journal-1.txt"), O_RDONLY|O_CLOEXEC); + journal_data_path = path_join(get_testdata_dir(), "journal-data/journal-1.txt"); + imp.fd = open(journal_data_path, O_RDONLY|O_CLOEXEC); assert_se(imp.fd >= 0); do @@ -49,9 +53,11 @@ static void test_basic_parsing(void) { static void test_bad_input(void) { _cleanup_(journal_importer_cleanup) JournalImporter imp = {}; + _cleanup_free_ char *journal_data_path = NULL; int r; - imp.fd = open(get_testdata_dir("/journal-data/journal-2.txt"), O_RDONLY|O_CLOEXEC); + journal_data_path = path_join(get_testdata_dir(), "journal-data/journal-2.txt"); + imp.fd = open(journal_data_path, O_RDONLY|O_CLOEXEC); assert_se(imp.fd >= 0); do @@ -63,8 +69,7 @@ static void test_bad_input(void) { } int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); test_basic_parsing(); test_bad_input(); diff --git a/src/test/test-json.c b/src/test/test-json.c new file mode 100644 index 0000000000..5aa4d19dbe --- /dev/null +++ b/src/test/test-json.c @@ -0,0 +1,462 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <math.h> +#if HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif + +#include "alloc-util.h" +#include "fd-util.h" +#include "json-internal.h" +#include "json.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_tokenizer(const char *data, ...) { + unsigned line = 0, column = 0; + void *state = NULL; + va_list ap; + + va_start(ap, data); + + for (;;) { + unsigned token_line, token_column; + _cleanup_free_ char *str = NULL; + JsonValue v = JSON_VALUE_NULL; + int t, tt; + + t = json_tokenize(&data, &str, &v, &token_line, &token_column, &state, &line, &column); + tt = va_arg(ap, int); + + assert_se(t == tt); + + if (t == JSON_TOKEN_END || t < 0) + break; + + else if (t == JSON_TOKEN_STRING) { + const char *nn; + + nn = va_arg(ap, const char *); + assert_se(streq_ptr(nn, str)); + + } else if (t == JSON_TOKEN_REAL) { + long double d; + + d = va_arg(ap, long double); + +#if HAVE_VALGRIND_VALGRIND_H + if (!RUNNING_ON_VALGRIND) +#endif + /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit: + * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits */ + assert_se(fabsl(d - v.real) < 0.001L); + + } else if (t == JSON_TOKEN_INTEGER) { + intmax_t i; + + i = va_arg(ap, intmax_t); + assert_se(i == v.integer); + + } else if (t == JSON_TOKEN_UNSIGNED) { + uintmax_t u; + + u = va_arg(ap, uintmax_t); + assert_se(u == v.unsig); + + } else if (t == JSON_TOKEN_BOOLEAN) { + bool b; + + b = va_arg(ap, int); + assert_se(b == v.boolean); + } + } + + va_end(ap); +} + +typedef void (*Test)(JsonVariant *); + +static void test_variant(const char *data, Test test) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; + _cleanup_free_ char *s = NULL; + int r; + + r = json_parse(data, &v, NULL, NULL); + assert_se(r == 0); + assert_se(v); + + r = json_variant_format(v, 0, &s); + assert_se(r >= 0); + assert_se(s); + + log_info("formatted normally: %s\n", s); + + r = json_parse(data, &w, NULL, NULL); + assert_se(r == 0); + assert_se(w); + assert_se(json_variant_has_type(v, json_variant_type(w))); + assert_se(json_variant_has_type(w, json_variant_type(v))); + assert_se(json_variant_equal(v, w)); + + s = mfree(s); + w = json_variant_unref(w); + + r = json_variant_format(v, JSON_FORMAT_PRETTY, &s); + assert_se(r >= 0); + assert_se(s); + + log_info("formatted prettily:\n%s", s); + + r = json_parse(data, &w, NULL, NULL); + assert_se(r == 0); + assert_se(w); + + assert_se(json_variant_has_type(v, json_variant_type(w))); + assert_se(json_variant_has_type(w, json_variant_type(v))); + assert_se(json_variant_equal(v, w)); + + s = mfree(s); + r = json_variant_format(v, JSON_FORMAT_COLOR, &s); + assert_se(r >= 0); + assert_se(s); + printf("Normal with color: %s\n", s); + + s = mfree(s); + r = json_variant_format(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, &s); + assert_se(r >= 0); + assert_se(s); + printf("Pretty with color:\n%s\n", s); + + if (test) + test(v); +} + +static void test_1(JsonVariant *v) { + JsonVariant *p, *q; + unsigned i; + + /* 3 keys + 3 values */ + assert_se(json_variant_elements(v) == 6); + + /* has k */ + p = json_variant_by_key(v, "k"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_STRING); + + /* k equals v */ + assert_se(streq(json_variant_string(p), "v")); + + /* has foo */ + p = json_variant_by_key(v, "foo"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 3); + + /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */ + for (i = 0; i < 3; ++i) { + q = json_variant_by_index(p, i); + assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == (i+1)); + assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == (i+1)); + } + + /* has bar */ + p = json_variant_by_key(v, "bar"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_OBJECT && json_variant_elements(p) == 2); + + /* zap is null */ + q = json_variant_by_key(p, "zap"); + assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL); +} + +static void test_2(JsonVariant *v) { + JsonVariant *p, *q; + + /* 2 keys + 2 values */ + assert_se(json_variant_elements(v) == 4); + + /* has mutant */ + p = json_variant_by_key(v, "mutant"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 4); + + /* mutant[0] == 1 */ + q = json_variant_by_index(p, 0); + assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1); + assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1); + + /* mutant[1] == null */ + q = json_variant_by_index(p, 1); + assert_se(q && json_variant_type(q) == JSON_VARIANT_NULL); + + /* mutant[2] == "1" */ + q = json_variant_by_index(p, 2); + assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); + + /* mutant[3] == JSON_VARIANT_OBJECT */ + q = json_variant_by_index(p, 3); + assert_se(q && json_variant_type(q) == JSON_VARIANT_OBJECT && json_variant_elements(q) == 2); + + /* has 1 */ + p = json_variant_by_key(q, "1"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_ARRAY && json_variant_elements(p) == 2); + + /* "1"[0] == 1 */ + q = json_variant_by_index(p, 0); + assert_se(q && json_variant_type(q) == JSON_VARIANT_UNSIGNED && json_variant_unsigned(q) == 1); + assert_se(q && json_variant_has_type(q, JSON_VARIANT_INTEGER) && json_variant_integer(q) == 1); + + /* "1"[1] == "1" */ + q = json_variant_by_index(p, 1); + assert_se(q && json_variant_type(q) == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); + + /* has thisisaverylongproperty */ + p = json_variant_by_key(v, "thisisaverylongproperty"); + assert_se(p && json_variant_type(p) == JSON_VARIANT_REAL && fabsl(json_variant_real(p) - 1.27) < 0.001); +} + + +static void test_zeroes(JsonVariant *v) { + size_t i; + + /* Make sure zero is how we expect it. */ + + assert_se(json_variant_elements(v) == 13); + + for (i = 0; i < json_variant_elements(v); i++) { + JsonVariant *w; + size_t j; + + assert_se(w = json_variant_by_index(v, i)); + + assert_se(json_variant_integer(w) == 0); + assert_se(json_variant_unsigned(w) == 0U); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + assert_se(json_variant_real(w) == 0.0L); +#pragma GCC diagnostic pop + + assert_se(json_variant_is_integer(w)); + assert_se(json_variant_is_unsigned(w)); + assert_se(json_variant_is_real(w)); + assert_se(json_variant_is_number(w)); + + assert_se(!json_variant_is_negative(w)); + + assert_se(IN_SET(json_variant_type(w), JSON_VARIANT_INTEGER, JSON_VARIANT_UNSIGNED, JSON_VARIANT_REAL)); + + for (j = 0; j < json_variant_elements(v); j++) { + JsonVariant *q; + + assert_se(q = json_variant_by_index(v, j)); + + assert_se(json_variant_equal(w, q)); + } + } +} + +static void test_build(void) { + _cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL; + _cleanup_free_ char *s = NULL, *t = NULL; + + assert_se(json_build(&a, JSON_BUILD_STRING("hallo")) >= 0); + assert_se(json_build(&b, JSON_BUILD_LITERAL(" \"hallo\" ")) >= 0); + assert_se(json_variant_equal(a, b)); + + b = json_variant_unref(b); + + assert_se(json_build(&b, JSON_BUILD_VARIANT(a)) >= 0); + assert_se(json_variant_equal(a, b)); + + b = json_variant_unref(b); + assert_se(json_build(&b, JSON_BUILD_STRING("pief")) >= 0); + assert_se(!json_variant_equal(a, b)); + + a = json_variant_unref(a); + b = json_variant_unref(b); + + assert_se(json_build(&a, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("one", JSON_BUILD_INTEGER(7)), + JSON_BUILD_PAIR("two", JSON_BUILD_REAL(2.0)), + JSON_BUILD_PAIR("three", JSON_BUILD_INTEGER(0)))) >= 0); + + assert_se(json_build(&b, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("two", JSON_BUILD_INTEGER(2)), + JSON_BUILD_PAIR("three", JSON_BUILD_REAL(0)), + JSON_BUILD_PAIR("one", JSON_BUILD_REAL(7)))) >= 0); + + assert_se(json_variant_equal(a, b)); + + a = json_variant_unref(a); + b = json_variant_unref(b); + + assert_se(json_build(&a, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)), + JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL)))), + JSON_BUILD_VARIANT(NULL), + JSON_BUILD_LITERAL(NULL), + JSON_BUILD_STRING(NULL), + JSON_BUILD_NULL, + JSON_BUILD_INTEGER(77), + JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")), JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))), + JSON_BUILD_STRV(STRV_MAKE("one", "two", "three", "four")))) >= 0); + + assert_se(json_variant_format(a, 0, &s) >= 0); + log_info("GOT: %s\n", s); + assert_se(json_parse(s, &b, NULL, NULL) >= 0); + assert_se(json_variant_equal(a, b)); + + a = json_variant_unref(a); + b = json_variant_unref(b); + + assert_se(json_build(&a, JSON_BUILD_REAL(M_PIl)) >= 0); + + s = mfree(s); + assert_se(json_variant_format(a, 0, &s) >= 0); + log_info("GOT: %s\n", s); + assert_se(json_parse(s, &b, NULL, NULL) >= 0); + assert_se(json_variant_format(b, 0, &t) >= 0); + log_info("GOT: %s\n", t); + + assert_se(streq(s, t)); + + a = json_variant_unref(a); + b = json_variant_unref(b); + + assert_se(json_build(&a, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")), + JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")), + JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c")) + )) >= 0); + + assert_se(json_build(&b, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")), + JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")), + JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")), + JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))), + JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c")) + )) >= 0); + + assert_se(json_variant_equal(a, b)); +} + +static void test_source(void) { + static const char data[] = + "\n" + "\n" + "{\n" + "\"foo\" : \"bar\", \n" + "\"qüüx\" : [ 1, 2, 3,\n" + "4,\n" + "5 ],\n" + "\"miep\" : { \"hallo\" : 1 },\n" + "\n" + "\"zzzzzz\" \n" + ":\n" + "[ true, \n" + "false, 7.5, {} ]\n" + "}\n"; + + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + + printf("--- original begin ---\n" + "%s" + "--- original end ---\n", data); + + assert_se(f = fmemopen((void*) data, strlen(data), "r")); + + assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0); + + printf("--- non-pretty begin ---\n"); + json_variant_dump(v, 0, stdout, NULL); + printf("\n--- non-pretty end ---\n"); + + printf("--- pretty begin ---\n"); + json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR|JSON_FORMAT_SOURCE, stdout, NULL); + printf("--- pretty end ---\n"); +} + +static void test_depth(void) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + unsigned i; + int r; + + v = JSON_VARIANT_STRING_CONST("start"); + + /* Let's verify that the maximum depth checks work */ + + for (i = 0;; i++) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + + assert_se(i <= UINT16_MAX); + if (i & 1) + r = json_variant_new_array(&w, &v, 1); + else + r = json_variant_new_object(&w, (JsonVariant*[]) { JSON_VARIANT_STRING_CONST("key"), v }, 2); + if (r == -ELNRNG) { + log_info("max depth at %u", i); + break; + } + + assert_se(r >= 0); + + json_variant_unref(v); + v = TAKE_PTR(w); + } + + json_variant_dump(v, 0, stdout, NULL); + fputs("\n", stdout); +} + +int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + test_tokenizer("x", -EINVAL); + test_tokenizer("", JSON_TOKEN_END); + test_tokenizer(" ", JSON_TOKEN_END); + test_tokenizer("0", JSON_TOKEN_UNSIGNED, (uintmax_t) 0, JSON_TOKEN_END); + test_tokenizer("-0", JSON_TOKEN_INTEGER, (intmax_t) 0, JSON_TOKEN_END); + test_tokenizer("1234", JSON_TOKEN_UNSIGNED, (uintmax_t) 1234, JSON_TOKEN_END); + test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END); + test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED, (uintmax_t) UINT64_MAX, JSON_TOKEN_END); + test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER, (intmax_t) INT64_MIN, JSON_TOKEN_END); + test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (long double) 18446744073709551616.0L, JSON_TOKEN_END); + test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (long double) -9223372036854775809.0L, JSON_TOKEN_END); + test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END); + test_tokenizer("3.141", JSON_TOKEN_REAL, (long double) 3.141, JSON_TOKEN_END); + test_tokenizer("0.0", JSON_TOKEN_REAL, (long double) 0.0, JSON_TOKEN_END); + test_tokenizer("7e3", JSON_TOKEN_REAL, (long double) 7e3, JSON_TOKEN_END); + test_tokenizer("-7e-3", JSON_TOKEN_REAL, (long double) -7e-3, JSON_TOKEN_END); + test_tokenizer("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END); + test_tokenizer("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END); + test_tokenizer("null", JSON_TOKEN_NULL, JSON_TOKEN_END); + test_tokenizer("{}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); + test_tokenizer("\t {\n} \n", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); + test_tokenizer("[]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END); + test_tokenizer("\t [] \n\n", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END); + test_tokenizer("\"\"", JSON_TOKEN_STRING, "", JSON_TOKEN_END); + test_tokenizer("\"foo\"", JSON_TOKEN_STRING, "foo", JSON_TOKEN_END); + test_tokenizer("\"foo\\nfoo\"", JSON_TOKEN_STRING, "foo\nfoo", JSON_TOKEN_END); + test_tokenizer("{\"foo\" : \"bar\"}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_STRING, "foo", JSON_TOKEN_COLON, JSON_TOKEN_STRING, "bar", JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); + test_tokenizer("{\"foo\" : [true, false]}", JSON_TOKEN_OBJECT_OPEN, JSON_TOKEN_STRING, "foo", JSON_TOKEN_COLON, JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_COMMA, JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_OBJECT_CLOSE, JSON_TOKEN_END); + test_tokenizer("\"\xef\xbf\xbd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END); + test_tokenizer("\"\\ufffd\"", JSON_TOKEN_STRING, "\xef\xbf\xbd", JSON_TOKEN_END); + test_tokenizer("\"\\uf\"", -EINVAL); + test_tokenizer("\"\\ud800a\"", -EINVAL); + test_tokenizer("\"\\udc00\\udc00\"", -EINVAL); + test_tokenizer("\"\\ud801\\udc37\"", JSON_TOKEN_STRING, "\xf0\x90\x90\xb7", JSON_TOKEN_END); + + test_tokenizer("[1, 2, -3]", JSON_TOKEN_ARRAY_OPEN, JSON_TOKEN_UNSIGNED, (uintmax_t) 1, JSON_TOKEN_COMMA, JSON_TOKEN_UNSIGNED, (uintmax_t) 2, JSON_TOKEN_COMMA, JSON_TOKEN_INTEGER, (intmax_t) -3, JSON_TOKEN_ARRAY_CLOSE, JSON_TOKEN_END); + + test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1); + test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2); + test_variant("{\"foo\" : \"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFF\"}", NULL); + + test_variant("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes); + + test_build(); + + test_source(); + + test_depth(); + + return 0; +} diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 68399bdb9e..10bf365035 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -1,18 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <errno.h> #include <getopt.h> #include <stdio.h> #include <sys/epoll.h> #include <unistd.h> -#include "libudev.h" - +#include "alloc-util.h" #include "fd-util.h" +#include "libudev-list-internal.h" +#include "libudev-util.h" #include "log.h" #include "stdio-util.h" #include "string-util.h" -#include "udev-util.h" -#include "util.h" static void print_device(struct udev_device *device) { const char *str; @@ -331,6 +331,138 @@ static void test_hwdb(struct udev *udev, const char *modalias) { assert_se(hwdb == NULL); } +static void test_util_replace_whitespace_one_len(const char *str, size_t len, const char *expected) { + _cleanup_free_ char *result = NULL; + int r; + + result = new(char, len + 1); + assert_se(result); + r = util_replace_whitespace(str, result, len); + assert_se((size_t) r == strlen(expected)); + assert_se(streq(result, expected)); +} + +static void test_util_replace_whitespace_one(const char *str, const char *expected) { + test_util_replace_whitespace_one_len(str, strlen(str), expected); +} + +static void test_util_replace_whitespace(void) { + test_util_replace_whitespace_one("hogehoge", "hogehoge"); + test_util_replace_whitespace_one("hoge hoge", "hoge_hoge"); + test_util_replace_whitespace_one(" hoge hoge ", "hoge_hoge"); + test_util_replace_whitespace_one(" ", ""); + test_util_replace_whitespace_one("hoge ", "hoge"); + + test_util_replace_whitespace_one_len("hoge hoge ", 9, "hoge_hoge"); + test_util_replace_whitespace_one_len("hoge hoge ", 8, "hoge_hog"); + test_util_replace_whitespace_one_len("hoge hoge ", 7, "hoge_ho"); + test_util_replace_whitespace_one_len("hoge hoge ", 6, "hoge_h"); + test_util_replace_whitespace_one_len("hoge hoge ", 5, "hoge"); + test_util_replace_whitespace_one_len("hoge hoge ", 4, "hoge"); + test_util_replace_whitespace_one_len("hoge hoge ", 3, "hog"); + test_util_replace_whitespace_one_len("hoge hoge ", 2, "ho"); + test_util_replace_whitespace_one_len("hoge hoge ", 1, "h"); + test_util_replace_whitespace_one_len("hoge hoge ", 0, ""); + + test_util_replace_whitespace_one_len(" hoge hoge ", 9, "hoge_hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 8, "hoge_hog"); + test_util_replace_whitespace_one_len(" hoge hoge ", 7, "hoge_ho"); + test_util_replace_whitespace_one_len(" hoge hoge ", 6, "hoge_h"); + test_util_replace_whitespace_one_len(" hoge hoge ", 5, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 4, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 3, "hog"); + test_util_replace_whitespace_one_len(" hoge hoge ", 2, "ho"); + test_util_replace_whitespace_one_len(" hoge hoge ", 1, "h"); + test_util_replace_whitespace_one_len(" hoge hoge ", 0, ""); +} + +static void test_util_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) { + char result[UTIL_PATH_SIZE]; + int r; + + r = util_resolve_subsys_kernel(str, result, sizeof(result), read_value); + assert_se(r == retval); + if (r >= 0) + assert_se(streq(result, expected)); +} + +static void test_util_resolve_subsys_kernel(void) { + test_util_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL); + test_util_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL); + test_util_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL); + test_util_resolve_subsys_kernel_one("[hoge/]", false, -ENODEV, NULL); + + test_util_resolve_subsys_kernel_one("[net/lo]", false, 0, "/sys/devices/virtual/net/lo"); + test_util_resolve_subsys_kernel_one("[net/lo]/", false, 0, "/sys/devices/virtual/net/lo"); + test_util_resolve_subsys_kernel_one("[net/lo]hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); + test_util_resolve_subsys_kernel_one("[net/lo]/hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); + + test_util_resolve_subsys_kernel_one("[net/lo]", true, -EINVAL, NULL); + test_util_resolve_subsys_kernel_one("[net/lo]/", true, -EINVAL, NULL); + test_util_resolve_subsys_kernel_one("[net/lo]hoge", true, 0, ""); + test_util_resolve_subsys_kernel_one("[net/lo]/hoge", true, 0, ""); + test_util_resolve_subsys_kernel_one("[net/lo]address", true, 0, "00:00:00:00:00:00"); + test_util_resolve_subsys_kernel_one("[net/lo]/address", true, 0, "00:00:00:00:00:00"); +} + +static void test_list(void) { + struct udev_list list = {}; + struct udev_list_entry *e; + + /* empty list */ + udev_list_init(&list, false); + assert_se(!udev_list_get_entry(&list)); + + /* unique == false */ + udev_list_init(&list, false); + assert_se(udev_list_entry_add(&list, "aaa", "hoge")); + assert_se(udev_list_entry_add(&list, "aaa", "hogehoge")); + assert_se(udev_list_entry_add(&list, "bbb", "foo")); + e = udev_list_get_entry(&list); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "hoge")); + e = udev_list_entry_get_next(e); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "hogehoge")); + e = udev_list_entry_get_next(e); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "bbb")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "foo")); + assert_se(!udev_list_entry_get_next(e)); + + assert_se(!udev_list_entry_get_by_name(e, "aaa")); + assert_se(!udev_list_entry_get_by_name(e, "bbb")); + assert_se(!udev_list_entry_get_by_name(e, "ccc")); + udev_list_cleanup(&list); + + /* unique == true */ + udev_list_init(&list, true); + assert_se(udev_list_entry_add(&list, "aaa", "hoge")); + assert_se(udev_list_entry_add(&list, "aaa", "hogehoge")); + assert_se(udev_list_entry_add(&list, "bbb", "foo")); + e = udev_list_get_entry(&list); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "hogehoge")); + e = udev_list_entry_get_next(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "bbb")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "foo")); + assert_se(!udev_list_entry_get_next(e)); + + e = udev_list_entry_get_by_name(e, "bbb"); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "bbb")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "foo")); + e = udev_list_entry_get_by_name(e, "aaa"); + assert_se(e); + assert_se(streq_ptr(udev_list_entry_get_name(e), "aaa")); + assert_se(streq_ptr(udev_list_entry_get_value(e), "hogehoge")); + assert_se(!udev_list_entry_get_by_name(e, "ccc")); + udev_list_cleanup(&list); +} + int main(int argc, char *argv[]) { _cleanup_(udev_unrefp) struct udev *udev = NULL; bool arg_monitor = false; @@ -399,7 +531,6 @@ int main(int argc, char *argv[]) { test_device_subsys_name(udev, "subsystem", "pci"); test_device_subsys_name(udev, "drivers", "scsi:sd"); test_device_subsys_name(udev, "module", "printk"); - test_device_parents(udev, syspath); test_enumerate(udev, subsystem); @@ -411,5 +542,10 @@ int main(int argc, char *argv[]) { if (arg_monitor) test_monitor(udev); + test_util_replace_whitespace(); + test_util_resolve_subsys_kernel(); + + test_list(); + return EXIT_SUCCESS; } diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 8ffae8ca03..c6f8c1fb4f 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -65,21 +65,32 @@ static void test_keymaps(void) { #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x)) static void dump_special_glyphs(void) { - assert_cc(ELLIPSIS + 1 == _SPECIAL_GLYPH_MAX); + assert_cc(SPECIAL_GLYPH_DEPRESSED_SMILEY + 1 == _SPECIAL_GLYPH_MAX); log_info("/* %s */", __func__); log_info("is_locale_utf8: %s", yes_no(is_locale_utf8())); - dump_glyph(TREE_VERTICAL); - dump_glyph(TREE_BRANCH); - dump_glyph(TREE_RIGHT); - dump_glyph(TREE_SPACE); - dump_glyph(TRIANGULAR_BULLET); - dump_glyph(BLACK_CIRCLE); - dump_glyph(ARROW); - dump_glyph(MDASH); - dump_glyph(ELLIPSIS); + dump_glyph(SPECIAL_GLYPH_TREE_VERTICAL); + dump_glyph(SPECIAL_GLYPH_TREE_BRANCH); + dump_glyph(SPECIAL_GLYPH_TREE_RIGHT); + dump_glyph(SPECIAL_GLYPH_TREE_SPACE); + dump_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET); + dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE); + dump_glyph(SPECIAL_GLYPH_BULLET); + dump_glyph(SPECIAL_GLYPH_ARROW); + dump_glyph(SPECIAL_GLYPH_MDASH); + dump_glyph(SPECIAL_GLYPH_ELLIPSIS); + dump_glyph(SPECIAL_GLYPH_MU); + dump_glyph(SPECIAL_GLYPH_CHECK_MARK); + dump_glyph(SPECIAL_GLYPH_CROSS_MARK); + dump_glyph(SPECIAL_GLYPH_ECSTATIC_SMILEY); + dump_glyph(SPECIAL_GLYPH_HAPPY_SMILEY); + dump_glyph(SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY); + dump_glyph(SPECIAL_GLYPH_NEUTRAL_SMILEY); + dump_glyph(SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY); + dump_glyph(SPECIAL_GLYPH_UNHAPPY_SMILEY); + dump_glyph(SPECIAL_GLYPH_DEPRESSED_SMILEY); } int main(int argc, char *argv[]) { diff --git a/src/test/test-log.c b/src/test/test-log.c index c09f40c356..1e010c08fb 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -17,20 +17,27 @@ assert_cc((LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, LOG_LOCAL3 | LOG_DEBUG) & LOG assert_cc((LOG_REALM_PLUS_LEVEL(LOG_REALM_UDEV, LOG_USER | LOG_INFO) & LOG_PRIMASK) == LOG_INFO); +assert_cc(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(EINVAL))); +assert_cc(!IS_SYNTHETIC_ERRNO(EINVAL)); +assert_cc(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(0))); +assert_cc(!IS_SYNTHETIC_ERRNO(0)); + #define X10(x) x x x x x x x x x x #define X100(x) X10(X10(x)) #define X1000(x) X100(X10(x)) -static void test_log_console(void) { +static void test_log_struct(void) { log_struct(LOG_INFO, - "MESSAGE=Waldo PID="PID_FMT, getpid_cached(), + "MESSAGE=Waldo PID="PID_FMT" (no errno)", getpid_cached(), "SERVICE=piepapo"); -} -static void test_log_journal(void) { - log_struct(LOG_INFO, - "MESSAGE=Foobar PID="PID_FMT, getpid_cached(), - "SERVICE=foobar"); + log_struct_errno(LOG_INFO, EILSEQ, + "MESSAGE=Waldo PID="PID_FMT": %m (normal)", getpid_cached(), + "SERVICE=piepapo"); + + log_struct_errno(LOG_INFO, SYNTHETIC_ERRNO(EILSEQ), + "MESSAGE=Waldo PID="PID_FMT": %m (synthetic)", getpid_cached(), + "SERVICE=piepapo"); log_struct(LOG_INFO, "MESSAGE=Foobar PID="PID_FMT, getpid_cached(), @@ -59,10 +66,11 @@ int main(int argc, char* argv[]) { log_set_target(target); log_open(); - test_log_console(); - test_log_journal(); + test_log_struct(); test_long_lines(); } + assert_se(log_info_errno(SYNTHETIC_ERRNO(EUCLEAN), "foo") == -EUCLEAN); + return 0; } diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index eaea9e4c76..89b760fae4 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -5,13 +5,12 @@ #include "log.h" #include "loopback-setup.h" +#include "tests.h" int main(int argc, char* argv[]) { int r; - log_open(); - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); r = loopback_setup(); if (r < 0) diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c index c10e1681fb..6986405dc6 100644 --- a/src/test/test-mount-util.c +++ b/src/test/test-mount-util.c @@ -3,241 +3,9 @@ #include <sys/mount.h> #include "alloc-util.h" -#include "def.h" -#include "fd-util.h" -#include "fileio.h" -#include "hashmap.h" -#include "log.h" -#include "log.h" #include "mount-util.h" -#include "path-util.h" -#include "rm-rf.h" #include "string-util.h" - -static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) { - long unsigned flags; - - assert_se(mount_propagation_flags_from_string(name, &flags) == ret); - - if (ret >= 0) { - const char *c; - - assert_se(flags == expected); - - c = mount_propagation_flags_to_string(flags); - if (isempty(name)) - assert_se(isempty(c)); - else - assert_se(streq(c, name)); - } -} - -static void test_mnt_id(void) { - _cleanup_fclose_ FILE *f = NULL; - Hashmap *h; - Iterator i; - char *p; - void *k; - int r; - - assert_se(f = fopen("/proc/self/mountinfo", "re")); - assert_se(h = hashmap_new(&trivial_hash_ops)); - - for (;;) { - _cleanup_free_ char *line = NULL, *path = NULL; - int mnt_id; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r == 0) - break; - assert_se(r > 0); - - assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2); - - assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0); - path = NULL; - } - - HASHMAP_FOREACH_KEY(p, k, h, i) { - int mnt_id = PTR_TO_INT(k), mnt_id2; - - r = path_get_mnt_id(p, &mnt_id2); - if (r < 0) { - log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p); - continue; - } - - log_debug("mnt id of %s is %i\n", p, mnt_id2); - - if (mnt_id == mnt_id2) - continue; - - /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really - * the case */ - assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p)); - } - - hashmap_free_free(h); -} - -static void test_path_is_mount_point(void) { - int fd; - char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; - _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; - _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL; - _cleanup_free_ char *dir2 = NULL, *dir2file = NULL; - - assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("/", NULL, 0) > 0); - assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("//", NULL, 0) > 0); - - assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("/proc", NULL, 0) > 0); - assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("/proc/", NULL, 0) > 0); - - assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0); - assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0); - - assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("/sys", NULL, 0) > 0); - assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0); - assert_se(path_is_mount_point("/sys/", NULL, 0) > 0); - - /* we'll create a hierarchy of different kinds of dir/file/link - * layouts: - * - * <tmp>/file1, <tmp>/file2 - * <tmp>/link1 -> file1, <tmp>/link2 -> file2 - * <tmp>/dir1/ - * <tmp>/dir1/file - * <tmp>/dirlink1 -> dir1 - * <tmp>/dirlink1file -> dirlink1/file - * <tmp>/dir2/ - * <tmp>/dir2/file - */ - - /* file mountpoints */ - assert_se(mkdtemp(tmp_dir) != NULL); - file1 = path_join(NULL, tmp_dir, "file1"); - assert_se(file1); - file2 = path_join(NULL, tmp_dir, "file2"); - assert_se(file2); - fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); - assert_se(fd > 0); - close(fd); - fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); - assert_se(fd > 0); - close(fd); - link1 = path_join(NULL, tmp_dir, "link1"); - assert_se(link1); - assert_se(symlink("file1", link1) == 0); - link2 = path_join(NULL, tmp_dir, "link2"); - assert_se(link1); - assert_se(symlink("file2", link2) == 0); - - assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(file1, NULL, 0) == 0); - assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(link1, NULL, 0) == 0); - - /* directory mountpoints */ - dir1 = path_join(NULL, tmp_dir, "dir1"); - assert_se(dir1); - assert_se(mkdir(dir1, 0755) == 0); - dirlink1 = path_join(NULL, tmp_dir, "dirlink1"); - assert_se(dirlink1); - assert_se(symlink("dir1", dirlink1) == 0); - dirlink1file = path_join(NULL, tmp_dir, "dirlink1file"); - assert_se(dirlink1file); - assert_se(symlink("dirlink1/file", dirlink1file) == 0); - dir2 = path_join(NULL, tmp_dir, "dir2"); - assert_se(dir2); - assert_se(mkdir(dir2, 0755) == 0); - - assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(dir1, NULL, 0) == 0); - assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0); - - /* file in subdirectory mountpoints */ - dir1file = path_join(NULL, dir1, "file"); - assert_se(dir1file); - fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); - assert_se(fd > 0); - close(fd); - - assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(dir1file, NULL, 0) == 0); - assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0); - assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0); - - /* these tests will only work as root */ - if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { - int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t; - const char *file2d; - - /* files */ - /* capture results in vars, to avoid dangling mounts on failure */ - log_info("%s: %s", __func__, file2); - rf = path_is_mount_point(file2, NULL, 0); - rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW); - - file2d = strjoina(file2, "/"); - log_info("%s: %s", __func__, file2d); - rdf = path_is_mount_point(file2d, NULL, 0); - rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW); - - log_info("%s: %s", __func__, link2); - rlf = path_is_mount_point(link2, NULL, 0); - rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW); - - assert_se(umount(file2) == 0); - - assert_se(rf == 1); - assert_se(rt == 1); - assert_se(rdf == -ENOTDIR); - assert_se(rdt == -ENOTDIR); - assert_se(rlf == 0); - assert_se(rlt == 1); - - /* dirs */ - dir2file = path_join(NULL, dir2, "file"); - assert_se(dir2file); - fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); - assert_se(fd > 0); - close(fd); - - assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0); - - log_info("%s: %s", __func__, dir1); - rf = path_is_mount_point(dir1, NULL, 0); - rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW); - log_info("%s: %s", __func__, dirlink1); - rlf = path_is_mount_point(dirlink1, NULL, 0); - rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW); - log_info("%s: %s", __func__, dirlink1file); - /* its parent is a mount point, but not /file itself */ - rl1f = path_is_mount_point(dirlink1file, NULL, 0); - rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW); - - assert_se(umount(dir1) == 0); - - assert_se(rf == 1); - assert_se(rt == 1); - assert_se(rlf == 0); - assert_se(rlt == 1); - assert_se(rl1f == 0); - assert_se(rl1t == 0); - - } else - printf("Skipping bind mount file test: %m\n"); - - assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); -} +#include "tests.h" static void test_mount_option_mangle(void) { char *opts = NULL; @@ -294,19 +62,8 @@ static void test_mount_option_mangle(void) { } int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); - log_set_max_level(LOG_DEBUG); - - test_mount_propagation_flags("shared", 0, MS_SHARED); - test_mount_propagation_flags("slave", 0, MS_SLAVE); - test_mount_propagation_flags("private", 0, MS_PRIVATE); - test_mount_propagation_flags(NULL, 0, 0); - test_mount_propagation_flags("", 0, 0); - test_mount_propagation_flags("xxxx", -EINVAL, 0); - test_mount_propagation_flags(" ", -EINVAL, 0); - - test_mnt_id(); - test_path_is_mount_point(); test_mount_option_mangle(); return 0; diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c new file mode 100644 index 0000000000..6d8bee0d63 --- /dev/null +++ b/src/test/test-mountpoint-util.c @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <sys/mount.h> + +#include "alloc-util.h" +#include "def.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "log.h" +#include "log.h" +#include "mountpoint-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" +#include "tests.h" + +static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) { + long unsigned flags; + + log_info("/* %s(%s) */", __func__, name); + + assert_se(mount_propagation_flags_from_string(name, &flags) == ret); + + if (ret >= 0) { + const char *c; + + assert_se(flags == expected); + + c = mount_propagation_flags_to_string(flags); + if (isempty(name)) + assert_se(isempty(c)); + else + assert_se(streq(c, name)); + } +} + +static void test_mnt_id(void) { + _cleanup_fclose_ FILE *f = NULL; + Hashmap *h; + Iterator i; + char *p; + void *k; + int r; + + log_info("/* %s */", __func__); + + assert_se(f = fopen("/proc/self/mountinfo", "re")); + assert_se(h = hashmap_new(&trivial_hash_ops)); + + for (;;) { + _cleanup_free_ char *line = NULL, *path = NULL; + int mnt_id; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r == 0) + break; + assert_se(r > 0); + + assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2); + + log_debug("mountinfo: %s → %i", path, mnt_id); + + assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0); + path = NULL; + } + + HASHMAP_FOREACH_KEY(p, k, h, i) { + int mnt_id = PTR_TO_INT(k), mnt_id2; + + r = path_get_mnt_id(p, &mnt_id2); + if (r < 0) { + log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p); + continue; + } + + log_debug("mnt ids of %s are %i, %i\n", p, mnt_id, mnt_id2); + + if (mnt_id == mnt_id2) + continue; + + /* The ids don't match? If so, then there are two mounts on the same path, let's check if + * that's really the case */ + char *t = hashmap_get(h, INT_TO_PTR(mnt_id2)); + log_debug("the other path for mnt id %i is %s\n", mnt_id2, t); + assert_se(path_equal(p, t)); + } + + hashmap_free_free(h); +} + +static void test_path_is_mount_point(void) { + int fd; + char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; + _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; + _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL; + _cleanup_free_ char *dir2 = NULL, *dir2file = NULL; + + log_info("/* %s */", __func__); + + assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("/", NULL, 0) > 0); + assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("//", NULL, 0) > 0); + + assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("/proc", NULL, 0) > 0); + assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("/proc/", NULL, 0) > 0); + + assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0); + assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0); + + assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("/sys", NULL, 0) > 0); + assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(path_is_mount_point("/sys/", NULL, 0) > 0); + + /* we'll create a hierarchy of different kinds of dir/file/link + * layouts: + * + * <tmp>/file1, <tmp>/file2 + * <tmp>/link1 -> file1, <tmp>/link2 -> file2 + * <tmp>/dir1/ + * <tmp>/dir1/file + * <tmp>/dirlink1 -> dir1 + * <tmp>/dirlink1file -> dirlink1/file + * <tmp>/dir2/ + * <tmp>/dir2/file + */ + + /* file mountpoints */ + assert_se(mkdtemp(tmp_dir) != NULL); + file1 = path_join(tmp_dir, "file1"); + assert_se(file1); + file2 = path_join(tmp_dir, "file2"); + assert_se(file2); + fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); + assert_se(fd > 0); + close(fd); + fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); + assert_se(fd > 0); + close(fd); + link1 = path_join(tmp_dir, "link1"); + assert_se(link1); + assert_se(symlink("file1", link1) == 0); + link2 = path_join(tmp_dir, "link2"); + assert_se(link1); + assert_se(symlink("file2", link2) == 0); + + assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(file1, NULL, 0) == 0); + assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(link1, NULL, 0) == 0); + + /* directory mountpoints */ + dir1 = path_join(tmp_dir, "dir1"); + assert_se(dir1); + assert_se(mkdir(dir1, 0755) == 0); + dirlink1 = path_join(tmp_dir, "dirlink1"); + assert_se(dirlink1); + assert_se(symlink("dir1", dirlink1) == 0); + dirlink1file = path_join(tmp_dir, "dirlink1file"); + assert_se(dirlink1file); + assert_se(symlink("dirlink1/file", dirlink1file) == 0); + dir2 = path_join(tmp_dir, "dir2"); + assert_se(dir2); + assert_se(mkdir(dir2, 0755) == 0); + + assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(dir1, NULL, 0) == 0); + assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0); + + /* file in subdirectory mountpoints */ + dir1file = path_join(dir1, "file"); + assert_se(dir1file); + fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); + assert_se(fd > 0); + close(fd); + + assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(dir1file, NULL, 0) == 0); + assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0); + + /* these tests will only work as root */ + if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { + int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t; + const char *file2d; + + /* files */ + /* capture results in vars, to avoid dangling mounts on failure */ + log_info("%s: %s", __func__, file2); + rf = path_is_mount_point(file2, NULL, 0); + rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW); + + file2d = strjoina(file2, "/"); + log_info("%s: %s", __func__, file2d); + rdf = path_is_mount_point(file2d, NULL, 0); + rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW); + + log_info("%s: %s", __func__, link2); + rlf = path_is_mount_point(link2, NULL, 0); + rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW); + + assert_se(umount(file2) == 0); + + assert_se(rf == 1); + assert_se(rt == 1); + assert_se(rdf == -ENOTDIR); + assert_se(rdt == -ENOTDIR); + assert_se(rlf == 0); + assert_se(rlt == 1); + + /* dirs */ + dir2file = path_join(dir2, "file"); + assert_se(dir2file); + fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); + assert_se(fd > 0); + close(fd); + + assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0); + + log_info("%s: %s", __func__, dir1); + rf = path_is_mount_point(dir1, NULL, 0); + rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW); + log_info("%s: %s", __func__, dirlink1); + rlf = path_is_mount_point(dirlink1, NULL, 0); + rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW); + log_info("%s: %s", __func__, dirlink1file); + /* its parent is a mount point, but not /file itself */ + rl1f = path_is_mount_point(dirlink1file, NULL, 0); + rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW); + + assert_se(umount(dir1) == 0); + + assert_se(rf == 1); + assert_se(rt == 1); + assert_se(rlf == 0); + assert_se(rlt == 1); + assert_se(rl1f == 0); + assert_se(rl1t == 0); + + } else + printf("Skipping bind mount file test: %m\n"); + + assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_mount_propagation_flags("shared", 0, MS_SHARED); + test_mount_propagation_flags("slave", 0, MS_SLAVE); + test_mount_propagation_flags("private", 0, MS_PRIVATE); + test_mount_propagation_flags(NULL, 0, 0); + test_mount_propagation_flags("", 0, 0); + test_mount_propagation_flags("xxxx", -EINVAL, 0); + test_mount_propagation_flags(" ", -EINVAL, 0); + + test_mnt_id(); + test_path_is_mount_point(); + + return 0; +} diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index b202739719..cc2efecfd2 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -7,6 +7,7 @@ #include "namespace.h" #include "process-util.h" #include "string-util.h" +#include "tests.h" #include "util.h" static void test_tmpdir(const char *id, const char *A, const char *B) { @@ -46,16 +47,14 @@ static void test_tmpdir(const char *id, const char *A, const char *B) { assert_se(rmdir(b) >= 0); } -static void test_netns(void) { +static int test_netns(void) { _cleanup_close_pair_ int s[2] = { -1, -1 }; pid_t pid1, pid2, pid3; int r, n = 0; siginfo_t si; - if (geteuid() > 0) { - log_info("Skipping test: not root"); - exit(EXIT_TEST_SKIP); - } + if (geteuid() > 0) + return log_tests_skipped("not root"); assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0); @@ -102,6 +101,7 @@ static void test_netns(void) { n += si.si_status; assert_se(n == 1); + return EXIT_SUCCESS; } int main(int argc, char *argv[]) { @@ -109,8 +109,12 @@ int main(int argc, char *argv[]) { char boot_id[SD_ID128_STRING_MAX]; _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL; - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); + + if (!have_namespaces()) { + log_tests_skipped("Don't have namespace support"); + return EXIT_TEST_SKIP; + } assert_se(sd_id128_get_boot(&bid) >= 0); sd_id128_to_string(bid, boot_id); @@ -128,7 +132,5 @@ int main(int argc, char *argv[]) { test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz); - test_netns(); - - return 0; + return test_netns(); } diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index eed610b27a..1ebe8d1972 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -10,6 +10,7 @@ #include "macro.h" #include "module-util.h" +#include "tests.h" #include "util.h" static int load_module(const char *mod_name) { @@ -47,10 +48,14 @@ static int test_tunnel_configure(sd_netlink *rtnl) { /* skip test if module cannot be loaded */ r = load_module("ipip"); if (r < 0) - return EXIT_TEST_SKIP; + return log_tests_skipped_errno(r, "failed to load module 'ipip'"); + + r = load_module("sit"); + if (r < 0) + return log_tests_skipped_errno(r, "failed to load module 'sit'"); if (getuid() != 0) - return EXIT_TEST_SKIP; + return log_tests_skipped("not root"); /* IPIP tunnel */ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); @@ -76,10 +81,6 @@ static int test_tunnel_configure(sd_netlink *rtnl) { assert_se((m = sd_netlink_message_unref(m)) == NULL); - r = load_module("sit"); - if (r < 0) - return EXIT_TEST_SKIP; - /* sit */ assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0); assert_se(n); @@ -113,6 +114,8 @@ int main(int argc, char *argv[]) { sd_netlink *rtnl; int r; + test_setup_logging(LOG_INFO); + assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(rtnl); diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 4ab70f2306..d3dbb54ca1 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -6,6 +6,7 @@ #include "log.h" #include "namespace.h" +#include "tests.h" int main(int argc, char *argv[]) { const char * const writable[] = { @@ -43,7 +44,7 @@ int main(int argc, char *argv[]) { char tmp_dir[] = "/tmp/systemd-private-XXXXXX", var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX"; - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); assert_se(mkdtemp(tmp_dir)); assert_se(mkdtemp(var_tmp_dir)); diff --git a/src/test/test-nscd-flush.c b/src/test/test-nscd-flush.c new file mode 100644 index 0000000000..97c219596d --- /dev/null +++ b/src/test/test-nscd-flush.c @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "main-func.h" +#include "nscd-flush.h" +#include "strv.h" +#include "tests.h" + +static int run(int argc, char *argv[]) { + int r; + + test_setup_logging(LOG_DEBUG); + + r = nscd_flush_cache(STRV_MAKE("group", "passwd", "hosts")); + if (r < 0) + return log_error_errno(r, "Failed to flush NSCD cache"); + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 9e543e7557..20aa6cf01f 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -1,22 +1,22 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include <dlfcn.h> -#include <stdlib.h> #include <net/if.h> +#include <stdlib.h> +#include "af-list.h" +#include "alloc-util.h" +#include "errno-list.h" +#include "hexdecoct.h" +#include "hostname-util.h" +#include "in-addr-util.h" +#include "local-addresses.h" #include "log.h" #include "nss-util.h" #include "path-util.h" -#include "string-util.h" -#include "alloc-util.h" -#include "in-addr-util.h" -#include "hexdecoct.h" -#include "af-list.h" #include "stdio-util.h" +#include "string-util.h" #include "strv.h" -#include "errno-list.h" -#include "hostname-util.h" -#include "local-addresses.h" static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) { switch (status) { @@ -51,14 +51,12 @@ static const char* af_to_string(int family, char *buf, size_t buf_len) { } static void* open_handle(const char* dir, const char* module, int flags) { - const char *path; + const char *path = NULL; void *handle; - if (dir) { + if (dir) path = strjoina(dir, "/libnss_", module, ".so.2"); - if (access(path, F_OK) < 0) - path = strjoina(dir, "/.libs/libnss_", module, ".so.2"); - } else + if (!path || access(path, F_OK) < 0) path = strjoina("libnss_", module, ".so.2"); handle = dlopen(path, flags); @@ -397,9 +395,7 @@ static int test_one_module(const char* dir, log_info("======== %s ========", module); - handle = open_handle(streq(module, "dns") ? NULL : dir, - module, - RTLD_LAZY|RTLD_NODELETE); + handle = open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE); if (!handle) return -EINVAL; @@ -428,20 +424,19 @@ static int parse_argv(int argc, char **argv, size_t n_allocated = 0; if (argc > 1) - modules = strv_new(argv[1], NULL); + modules = strv_new(argv[1]); else modules = strv_new( -#if ENABLE_MYHOSTNAME +#if ENABLE_NSS_MYHOSTNAME "myhostname", #endif -#if ENABLE_RESOLVE +#if ENABLE_NSS_RESOLVE "resolve", #endif -#if ENABLE_MACHINED +#if ENABLE_NSS_MYMACHINES "mymachines", #endif - "dns", - NULL); + "dns"); if (!modules) return -ENOMEM; @@ -472,7 +467,7 @@ static int parse_argv(int argc, char **argv, if (!hostname) return -ENOMEM; - names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname, NULL); + names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname); if (!names) return -ENOMEM; diff --git a/src/test/test-os-util.c b/src/test/test-os-util.c index 8d8b52d7f6..c215a2e99e 100644 --- a/src/test/test-os-util.c +++ b/src/test/test-os-util.c @@ -4,6 +4,7 @@ #include "log.h" #include "os-util.h" +#include "tests.h" static void test_path_is_os_tree(void) { assert_se(path_is_os_tree("/") > 0); @@ -12,9 +13,7 @@ static void test_path_is_os_tree(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_path_is_os_tree(); diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index e9aef5e882..d732f402f0 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -726,10 +726,12 @@ static void test_parse_dev(void) { assert_se(parse_dev("5", &dev) == -EINVAL); assert_se(parse_dev("5:", &dev) == -EINVAL); assert_se(parse_dev(":5", &dev) == -EINVAL); + assert_se(parse_dev("-1:-1", &dev) == -EINVAL); #if SIZEOF_DEV_T < 8 assert_se(parse_dev("4294967295:4294967295", &dev) == -EINVAL); #endif assert_se(parse_dev("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11); + assert_se(parse_dev("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0); } static void test_parse_errno(void) { diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 892293cb10..f208559358 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -8,6 +8,7 @@ #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "tests.h" static void test_paths(UnitFileScope scope) { char template[] = "/tmp/test-path-lookup.XXXXXXX"; @@ -40,6 +41,8 @@ static void test_user_and_global_paths(void) { unsigned k = 0; assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); + assert_se(unsetenv("XDG_DATA_DIRS") == 0); + assert_se(unsetenv("XDG_CONFIG_DIRS") == 0); assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0); assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0); @@ -76,9 +79,7 @@ static void print_generator_binary_paths(UnitFileScope scope) { } int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_paths(UNIT_FILE_SYSTEM); test_paths(UNIT_FILE_USER); diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 35b27bcedd..8854a94f6c 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -6,12 +6,13 @@ #include "alloc-util.h" #include "fd-util.h" #include "macro.h" -#include "mount-util.h" +#include "mountpoint-util.h" #include "path-util.h" #include "rm-rf.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "util.h" #define test_path_compare(a, b, result) { \ @@ -80,10 +81,10 @@ static void test_path(void) { test_path_simplify("///.//", "/.", "/"); test_path_simplify("///.//.///", "/./.", "/"); test_path_simplify("////.././///../.", "/.././../.", "/../.."); - test_path_simplify(".", ".", ""); - test_path_simplify("./", ".", ""); - test_path_simplify(".///.//./.", "./././.", ""); - test_path_simplify(".///.//././/", "./././.", ""); + test_path_simplify(".", ".", "."); + test_path_simplify("./", ".", "."); + test_path_simplify(".///.//./.", "./././.", "."); + test_path_simplify(".///.//././/", "./././.", "."); test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", "/./aaa/././.bbb/../c./d.dd/..eeee/.", "/aaa/.bbb/../c./d.dd/..eeee"); @@ -231,23 +232,47 @@ static void test_prefixes(void) { static void test_path_join(void) { -#define test_join(root, path, rest, expected) { \ +#define test_join(expected, ...) { \ _cleanup_free_ char *z = NULL; \ - z = path_join(root, path, rest); \ + z = path_join(__VA_ARGS__); \ + log_debug("got \"%s\", expected \"%s\"", z, expected); \ assert_se(streq(z, expected)); \ } - test_join("/root", "/a/b", "/c", "/root/a/b/c"); - test_join("/root", "a/b", "c", "/root/a/b/c"); - test_join("/root", "/a/b", "c", "/root/a/b/c"); - test_join("/root", "/", "c", "/root/c"); - test_join("/root", "/", NULL, "/root/"); - - test_join(NULL, "/a/b", "/c", "/a/b/c"); - test_join(NULL, "a/b", "c", "a/b/c"); - test_join(NULL, "/a/b", "c", "/a/b/c"); - test_join(NULL, "/", "c", "/c"); - test_join(NULL, "/", NULL, "/"); + test_join("/root/a/b/c", "/root", "/a/b", "/c"); + test_join("/root/a/b/c", "/root", "a/b", "c"); + test_join("/root/a/b/c", "/root", "/a/b", "c"); + test_join("/root/c", "/root", "/", "c"); + test_join("/root/", "/root", "/", NULL); + + test_join("/a/b/c", "", "/a/b", "/c"); + test_join("a/b/c", "", "a/b", "c"); + test_join("/a/b/c", "", "/a/b", "c"); + test_join("/c", "", "/", "c"); + test_join("/", "", "/", NULL); + + test_join("/a/b/c", NULL, "/a/b", "/c"); + test_join("a/b/c", NULL, "a/b", "c"); + test_join("/a/b/c", NULL, "/a/b", "c"); + test_join("/c", NULL, "/", "c"); + test_join("/", NULL, "/", NULL); + + test_join("", "", NULL); + test_join("", NULL, ""); + test_join("", NULL, NULL); + + test_join("foo/bar", "foo", "bar"); + test_join("foo/bar", "", "foo", "bar"); + test_join("foo/bar", NULL, "foo", NULL, "bar"); + test_join("foo/bar", "", "foo", "", "bar", ""); + test_join("foo/bar", "", "", "", "", "foo", "", "", "", "bar", "", "", ""); + + test_join("//foo///bar//", "", "/", "", "/foo/", "", "/", "", "/bar/", "", "/", ""); + test_join("/foo/bar/", "/", "foo", "/", "bar", "/"); + test_join("foo/bar/baz", "foo", "bar", "baz"); + test_join("foo/bar/baz", "foo/", "bar", "/baz"); + test_join("foo//bar//baz", "foo/", "/bar/", "/baz"); + test_join("//foo////bar////baz//", "//foo/", "///bar/", "///baz//"); } static void test_fsck_exists(void) { @@ -292,7 +317,7 @@ static void test_strv_resolve(void) { assert_se(mkdtemp(tmp_dir) != NULL); - search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL); + search_dirs = strv_new("/dir1", "/dir2", "/dir3"); assert_se(search_dirs); STRV_FOREACH(d, search_dirs) { char *p = strappend(tmp_dir, *d); @@ -405,6 +430,7 @@ static void test_file_in_same_dir(void) { } static void test_last_path_component(void) { + assert_se(last_path_component(NULL) == NULL); assert_se(streq(last_path_component("a/b/c"), "c")); assert_se(streq(last_path_component("a/b/c/"), "c/")); assert_se(streq(last_path_component("/"), "/")); @@ -423,6 +449,45 @@ static void test_last_path_component(void) { assert_se(streq(last_path_component("/a/"), "a/")); } +static void test_path_extract_filename_one(const char *input, const char *output, int ret) { + _cleanup_free_ char *k = NULL; + int r; + + r = path_extract_filename(input, &k); + log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror(-r), strnull(output), strerror(-ret)); + assert_se(streq_ptr(k, output)); + assert_se(r == ret); +} + +static void test_path_extract_filename(void) { + test_path_extract_filename_one(NULL, NULL, -EINVAL); + test_path_extract_filename_one("a/b/c", "c", 0); + test_path_extract_filename_one("a/b/c/", "c", 0); + test_path_extract_filename_one("/", NULL, -EINVAL); + test_path_extract_filename_one("//", NULL, -EINVAL); + test_path_extract_filename_one("///", NULL, -EINVAL); + test_path_extract_filename_one(".", NULL, -EINVAL); + test_path_extract_filename_one("./.", NULL, -EINVAL); + test_path_extract_filename_one("././", NULL, -EINVAL); + test_path_extract_filename_one("././/", NULL, -EINVAL); + test_path_extract_filename_one("/foo/a", "a", 0); + test_path_extract_filename_one("/foo/a/", "a", 0); + test_path_extract_filename_one("", NULL, -EINVAL); + test_path_extract_filename_one("a", "a", 0); + test_path_extract_filename_one("a/", "a", 0); + test_path_extract_filename_one("/a", "a", 0); + test_path_extract_filename_one("/a/", "a", 0); + test_path_extract_filename_one("/////////////a/////////////", "a", 0); + test_path_extract_filename_one("xx/.", NULL, -EINVAL); + test_path_extract_filename_one("xx/..", NULL, -EINVAL); + test_path_extract_filename_one("..", NULL, -EINVAL); + test_path_extract_filename_one("/..", NULL, -EINVAL); + test_path_extract_filename_one("../", NULL, -EINVAL); + test_path_extract_filename_one(".", NULL, -EINVAL); + test_path_extract_filename_one("/.", NULL, -EINVAL); + test_path_extract_filename_one("./", NULL, -EINVAL); +} + static void test_filename_is_valid(void) { char foo[FILENAME_MAX+2]; int i; @@ -505,10 +570,29 @@ static void test_empty_or_root(void) { assert_se(!empty_or_root("//yy//")); } +static void test_path_startswith_set(void) { + + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/bar", "/zzz"), "")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/", "/zzz"), "bar")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo", "/zzz"), "bar")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/", "/zzz"), "foo/bar")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "", "/zzz"), NULL)); + + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo/bar", "/zzz"), NULL)); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo/", "/zzz"), "bar2")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo", "/zzz"), "bar2")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/", "/zzz"), "foo/bar2")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "", "/zzz"), NULL)); + + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo/bar", "/zzz"), NULL)); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo/", "/zzz"), NULL)); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo", "/zzz"), NULL)); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/", "/zzz"), "foo2/bar")); + assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "", "/zzz"), NULL)); +} + int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_path(); test_path_equal_root(); @@ -522,10 +606,12 @@ int main(int argc, char **argv) { test_prefix_root(); test_file_in_same_dir(); test_last_path_component(); + test_path_extract_filename(); test_filename_is_valid(); test_hidden_or_backup_file(); test_skip_dev_prefix(); test_empty_or_root(); + test_path_startswith_set(); test_systemd_installation_has_version(argv[1]); /* NULL is OK */ diff --git a/src/test/test-path.c b/src/test/test-path.c index 209eb2e366..07a0e413ee 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -12,6 +12,7 @@ #include "macro.h" #include "manager.h" #include "mkdir.h" +#include "path-util.h" #include "rm-rf.h" #include "string-util.h" #include "strv.h" @@ -32,16 +33,12 @@ static int setup_test(Manager **m) { assert_se(m); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping test: cgroupfs not available"); - return -EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return -EXIT_TEST_SKIP; - } + if (MANAGER_SKIP_TEST(r)) + return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); assert_se(manager_startup(tmp, NULL, NULL) >= 0); @@ -106,7 +103,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con } } - assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0); + assert_se(unit_stop(unit) >= 0); (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL); } @@ -117,7 +114,7 @@ static void test_path_exists(Manager *m) { assert_se(m); assert_se(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); assert_se(touch(test_path) >= 0); @@ -130,7 +127,7 @@ static void test_path_existsglob(Manager *m) { assert_se(m); assert_se(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); assert_se(touch(test_path) >= 0); @@ -147,7 +144,7 @@ static void test_path_changed(Manager *m) { assert_se(touch(test_path) >= 0); assert_se(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); f = fopen(test_path, "w"); assert_se(f); @@ -166,7 +163,7 @@ static void test_path_modified(Manager *m) { assert_se(touch(test_path) >= 0); assert_se(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); f = fopen(test_path, "w"); assert_se(f); @@ -182,7 +179,7 @@ static void test_path_unit(Manager *m) { assert_se(m); assert_se(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); assert_se(touch(test_path) >= 0); @@ -198,7 +195,7 @@ static void test_path_directorynotempty(Manager *m) { assert_se(access(test_path, F_OK) < 0); assert_se(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); /* MakeDirectory default to no */ assert_se(access(test_path, F_OK) < 0); @@ -219,7 +216,7 @@ static void test_path_makedirectory_directorymode(Manager *m) { assert_se(access(test_path, F_OK) < 0); assert_se(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit) >= 0); - assert_se(UNIT_VTABLE(unit)->start(unit) >= 0); + assert_se(unit_start(unit) >= 0); /* Check if the directory has been created */ assert_se(access(test_path, F_OK) >= 0); @@ -230,7 +227,7 @@ static void test_path_makedirectory_directorymode(Manager *m) { assert_se((s.st_mode & S_IRWXG) == 0040); assert_se((s.st_mode & S_IRWXO) == 0004); - assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0); + assert_se(unit_stop(unit) >= 0); (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL); } @@ -247,15 +244,16 @@ int main(int argc, char *argv[]) { }; _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + _cleanup_free_ char *test_path = NULL; const test_function_t *test = NULL; Manager *m = NULL; umask(022); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); - assert_se(set_unit_path(get_testdata_dir("/test-path")) >= 0); + test_path = path_join(get_testdata_dir(), "test-path"); + assert_se(set_unit_path(test_path) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); for (test = tests; test && *test; test++) { @@ -263,8 +261,8 @@ int main(int argc, char *argv[]) { /* We create a clean environment for each test */ r = setup_test(&m); - if (r < 0) - return -r; + if (r != 0) + return r; (*test)(m); diff --git a/src/test/test-pretty-print.c b/src/test/test-pretty-print.c new file mode 100644 index 0000000000..53ec512ec3 --- /dev/null +++ b/src/test/test-pretty-print.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <stdio.h> + +#include "alloc-util.h" +#include "macro.h" +#include "pretty-print.h" +#include "strv.h" +#include "tests.h" + +static void test_terminal_urlify(void) { + _cleanup_free_ char *formatted = NULL; + + assert_se(terminal_urlify("https://www.freedesktop.org/wiki/Software/systemd/", "systemd homepage", &formatted) >= 0); + printf("Hey, considere visiting the %s right now! It is very good!\n", formatted); + + formatted = mfree(formatted); + + assert_se(terminal_urlify_path("/etc/fstab", "this link to your /etc/fstab", &formatted) >= 0); + printf("Or click on %s to have a look at it!\n", formatted); +} + +static void test_cat_files(void) { + assert_se(cat_files("/no/such/file", NULL, 0) == -ENOENT); + assert_se(cat_files("/no/such/file", NULL, CAT_FLAGS_MAIN_FILE_OPTIONAL) == 0); + + if (access("/etc/fstab", R_OK) >= 0) + assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + test_terminal_urlify(); + test_cat_files(); + + print_separator(); + + return 0; +} diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index 89c41d8ce7..bc5fdd15b2 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -10,40 +10,30 @@ #define SET_SIZE 1024*4 -static int unsigned_compare(const void *a, const void *b) { - const unsigned *x = a, *y = b; - - if (*x < *y) - return -1; - - if (*x > *y) - return 1; - - return 0; +static int unsigned_compare(const unsigned *a, const unsigned *b) { + return CMP(*a, *b); } static void test_unsigned(void) { - unsigned buffer[SET_SIZE], i; - Prioq *q; + _cleanup_(prioq_freep) Prioq *q = NULL; + unsigned buffer[SET_SIZE], i, u, n; srand(0); - q = prioq_new(trivial_compare_func); - assert_se(q); + assert_se(q = prioq_new(trivial_compare_func)); for (i = 0; i < ELEMENTSOF(buffer); i++) { - unsigned u; - u = (unsigned) rand(); buffer[i] = u; assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0); + + n = prioq_size(q); + assert_se(prioq_remove(q, UINT_TO_PTR(u), &n) == 0); } - qsort(buffer, ELEMENTSOF(buffer), sizeof(buffer[0]), unsigned_compare); + typesafe_qsort(buffer, ELEMENTSOF(buffer), unsigned_compare); for (i = 0; i < ELEMENTSOF(buffer); i++) { - unsigned u; - assert_se(prioq_size(q) == ELEMENTSOF(buffer) - i); u = PTR_TO_UINT(prioq_pop(q)); @@ -51,7 +41,6 @@ static void test_unsigned(void) { } assert_se(prioq_isempty(q)); - prioq_free(q); } struct test { @@ -59,90 +48,59 @@ struct test { unsigned idx; }; -static int test_compare(const void *a, const void *b) { - const struct test *x = a, *y = b; - - if (x->value < y->value) - return -1; - - if (x->value > y->value) - return 1; - - return 0; +static int test_compare(const struct test *x, const struct test *y) { + return CMP(x->value, y->value); } -static void test_hash(const void *a, struct siphash *state) { - const struct test *x = a; - +static void test_hash(const struct test *x, struct siphash *state) { siphash24_compress(&x->value, sizeof(x->value), state); } -static const struct hash_ops test_hash_ops = { - .hash = test_hash, - .compare = test_compare -}; +DEFINE_PRIVATE_HASH_OPS(test_hash_ops, struct test, test_hash, test_compare); static void test_struct(void) { - Prioq *q; - Set *s; + _cleanup_(prioq_freep) Prioq *q = NULL; + _cleanup_(set_freep) Set *s = NULL; unsigned previous = 0, i; - int r; + struct test *t; srand(0); - q = prioq_new(test_compare); - assert_se(q); - - s = set_new(&test_hash_ops); - assert_se(s); + assert_se(q = prioq_new((compare_func_t) test_compare)); + assert_se(s = set_new(&test_hash_ops)); for (i = 0; i < SET_SIZE; i++) { - struct test *t; - - t = new0(struct test, 1); - assert_se(t); + assert_se(t = new0(struct test, 1)); t->value = (unsigned) rand(); - r = prioq_put(q, t, &t->idx); - assert_se(r >= 0); + assert_se(prioq_put(q, t, &t->idx) >= 0); - if (i % 4 == 0) { - r = set_consume(s, t); - assert_se(r >= 0); - } + if (i % 4 == 0) + assert_se(set_consume(s, t) >= 0); } - for (;;) { - struct test *t; - - t = set_steal_first(s); - if (!t) - break; - - r = prioq_remove(q, t, &t->idx); - assert_se(r > 0); + while ((t = set_steal_first(s))) { + assert_se(prioq_remove(q, t, &t->idx) == 1); + assert_se(prioq_remove(q, t, &t->idx) == 0); + assert_se(prioq_remove(q, t, NULL) == 0); free(t); } for (i = 0; i < SET_SIZE * 3 / 4; i++) { - struct test *t; - assert_se(prioq_size(q) == (SET_SIZE * 3 / 4) - i); - t = prioq_pop(q); - assert_se(t); - + assert_se(t = prioq_pop(q)); + assert_se(prioq_remove(q, t, &t->idx) == 0); + assert_se(prioq_remove(q, t, NULL) == 0); assert_se(previous <= t->value); + previous = t->value; free(t); } assert_se(prioq_isempty(q)); - prioq_free(q); - assert_se(set_isempty(s)); - set_free(s); } int main(int argc, char* argv[]) { diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 8f77e084b6..b0fc217d51 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" +#include "env-util.h" #include "log.h" #include "macro.h" #include "proc-cmdline.h" @@ -19,29 +20,79 @@ static int parse_item(const char *key, const char *value, void *data) { } static void test_proc_cmdline_parse(void) { - assert_se(proc_cmdline_parse(parse_item, &obj, true) >= 0); + log_info("/* %s */", __func__); + + assert_se(proc_cmdline_parse(parse_item, &obj, PROC_CMDLINE_STRIP_RD_PREFIX) >= 0); } -static void test_runlevel_to_target(void) { - in_initrd_force(false); - assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); - assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); - assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); +static void test_proc_cmdline_override(void) { + log_info("/* %s */", __func__); - in_initrd_force(true); - assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); - assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("3"), NULL)); - assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0); + + /* Test if the override works */ + _cleanup_free_ char *line = NULL, *value = NULL; + assert_se(proc_cmdline(&line) >= 0); + + /* Test if parsing makes uses of the override */ + assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"")); + assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("some_arg_with_space", 0, &value) > 0 && streq_ptr(value, "foo bar")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("and_one_more", 0, &value) > 0 && streq_ptr(value, "zzz aaa")); + value = mfree(value); +} + +static int parse_item_given(const char *key, const char *value, void *data) { + assert_se(key); + assert_se(data); + + bool *strip = data; + + log_info("%s: option <%s> = <%s>", __func__, key, strna(value)); + if (proc_cmdline_key_streq(key, "foo_bar")) + assert_se(streq(value, "quux")); + else if (proc_cmdline_key_streq(key, "wuff-piep")) + assert_se(streq(value, "tuet ")); + else if (proc_cmdline_key_streq(key, "space")) + assert_se(streq(value, "x y z")); + else if (proc_cmdline_key_streq(key, "miepf")) + assert_se(streq(value, "uuu")); + else if (in_initrd() && *strip && proc_cmdline_key_streq(key, "zumm")) + assert_se(!value); + else if (in_initrd() && !*strip && proc_cmdline_key_streq(key, "rd.zumm")) + assert_se(!value); + else + assert_not_reached("Bad key!"); + + return 0; +} + +static void test_proc_cmdline_given(bool flip_initrd) { + log_info("/* %s (flip: %s) */", __func__, yes_no(flip_initrd)); + + if (flip_initrd) + in_initrd_force(!in_initrd()); + + bool t = true, f = false; + assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm space='x y z' miepf=\"uuu\"", + parse_item_given, &t, PROC_CMDLINE_STRIP_RD_PREFIX) >= 0); + + assert_se(proc_cmdline_parse_given("foo_bar=quux wuff-piep=\"tuet \" rd.zumm space='x y z' miepf=\"uuu\"", + parse_item_given, &f, 0) >= 0); + + if (flip_initrd) + in_initrd_force(!in_initrd()); } static void test_proc_cmdline_get_key(void) { _cleanup_free_ char *value = NULL; - putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm"); + log_info("/* %s */", __func__); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm spaaace='ö ü ß' ticks=\"''\"") == 0); assert_se(proc_cmdline_get_key("", 0, &value) == -EINVAL); assert_se(proc_cmdline_get_key("abc", 0, NULL) == 0); @@ -73,12 +124,18 @@ static void test_proc_cmdline_get_key(void) { assert_se(proc_cmdline_get_key("zumm", 0, &value) == 0 && value == NULL); assert_se(proc_cmdline_get_key("zumm", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && value == NULL); assert_se(proc_cmdline_get_key("zumm", 0, NULL) > 0); + + assert_se(proc_cmdline_get_key("spaaace", 0, &value) > 0 && streq_ptr(value, "ö ü ß")); + value = mfree(value); + + assert_se(proc_cmdline_get_key("ticks", 0, &value) > 0 && streq_ptr(value, "''")); } static void test_proc_cmdline_get_bool(void) { bool value = false; - putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep"); + log_info("/* %s */", __func__); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep") == 0); assert_se(proc_cmdline_get_bool("", &value) == -EINVAL); assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false); @@ -93,7 +150,30 @@ static void test_proc_cmdline_get_bool(void) { assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false); } +static void test_proc_cmdline_get_key_many(void) { + _cleanup_free_ char *value1 = NULL, *value2 = NULL, *value3 = NULL, *value4 = NULL, *value5 = NULL, *value6 = NULL; + + log_info("/* %s */", __func__); + assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm SPACE='one two' doubleticks=\" aaa aaa \"") == 0); + + assert_se(proc_cmdline_get_key_many(0, + "wuff-piep", &value3, + "foo_bar", &value1, + "idontexist", &value2, + "zumm", &value4, + "SPACE", &value5, + "doubleticks", &value6) == 4); + + assert_se(streq_ptr(value1, "quux")); + assert_se(!value2); + assert_se(streq_ptr(value3, "tuet")); + assert_se(!value4); + assert_se(streq_ptr(value5, "one two")); + assert_se(streq_ptr(value6, " aaa aaa ")); +} + static void test_proc_cmdline_key_streq(void) { + log_info("/* %s */", __func__); assert_se(proc_cmdline_key_streq("", "")); assert_se(proc_cmdline_key_streq("a", "a")); @@ -110,6 +190,7 @@ static void test_proc_cmdline_key_streq(void) { } static void test_proc_cmdline_key_startswith(void) { + log_info("/* %s */", __func__); assert_se(proc_cmdline_key_startswith("", "")); assert_se(proc_cmdline_key_startswith("x", "")); @@ -124,15 +205,38 @@ static void test_proc_cmdline_key_startswith(void) { assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx")); } +static void test_runlevel_to_target(void) { + log_info("/* %s */", __func__); + + in_initrd_force(false); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); + + in_initrd_force(true); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); +} + int main(void) { log_parse_environment(); log_open(); test_proc_cmdline_parse(); + test_proc_cmdline_override(); + test_proc_cmdline_given(false); + /* Repeat the same thing, but now flip our ininitrdness */ + test_proc_cmdline_given(true); test_proc_cmdline_key_streq(); test_proc_cmdline_key_startswith(); test_proc_cmdline_get_key(); test_proc_cmdline_get_bool(); + test_proc_cmdline_get_key_many(); test_runlevel_to_target(); return 0; diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index fd4d17408d..5c87db08f5 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -17,6 +17,7 @@ #include "fd-util.h" #include "log.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "process-util.h" #include "signal-util.h" @@ -24,6 +25,7 @@ #include "string-util.h" #include "terminal-util.h" #include "test-helper.h" +#include "tests.h" #include "util.h" #include "virt.h" @@ -180,15 +182,24 @@ static void test_get_process_cmdline_harder(void) { _cleanup_free_ char *line = NULL; pid_t pid; - if (geteuid() != 0) + if (geteuid() != 0) { + log_info("Skipping %s: not root", __func__); return; + } + + if (!have_namespaces()) { + log_notice("Testing without namespaces, skipping %s", __func__); + return; + } #if HAVE_VALGRIND_VALGRIND_H /* valgrind patches open(/proc//cmdline) * so, test_get_process_cmdline_harder fails always * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */ - if (RUNNING_ON_VALGRIND) + if (RUNNING_ON_VALGRIND) { + log_info("Skipping %s: running on valgrind", __func__); return; + } #endif pid = fork(); @@ -206,15 +217,21 @@ static void test_get_process_cmdline_harder(void) { assert_se(pid == 0); assert_se(unshare(CLONE_NEWNS) >= 0); - assert_se(mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) >= 0); + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) { + log_warning_errno(errno, "mount(..., \"/\", MS_SLAVE|MS_REC, ...) failed: %m"); + assert_se(IN_SET(errno, EPERM, EACCES)); + return; + } fd = mkostemp(path, O_CLOEXEC); assert_se(fd >= 0); + /* Note that we don't unmount the following bind-mount at the end of the test because the kernel + * will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */ if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) { /* This happens under selinux… Abort the test in this case. */ log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m"); - assert(errno == EACCES); + assert_se(IN_SET(errno, EPERM, EACCES)); return; } @@ -394,12 +411,17 @@ static void test_rename_process_now(const char *p, int ret) { log_info("comm = <%s>", comm); assert_se(strneq(comm, p, TASK_COMM_LEN-1)); - assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0); + r = get_process_cmdline(0, 0, false, &cmdline); + assert_se(r >= 0); /* we cannot expect cmdline to be renamed properly without privileges */ if (geteuid() == 0) { - log_info("cmdline = <%s>", cmdline); - assert_se(strneq(p, cmdline, STRLEN("test-process-util"))); - assert_se(startswith(p, cmdline)); + if (r == 0 && detect_container() > 0) + log_info("cmdline = <%s> (not verified, Running in unprivileged container?)", cmdline); + else { + log_info("cmdline = <%s>", cmdline); + assert_se(strneq(p, cmdline, STRLEN("test-process-util"))); + assert_se(startswith(p, cmdline)); + } } else log_info("cmdline = <%s> (not verified)", cmdline); } @@ -581,9 +603,7 @@ static void test_ioprio_class_from_to_string(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); saved_argc = argc; saved_argv = argv; diff --git a/src/test/test-random-util.c b/src/test/test-random-util.c index a4760b54a3..94c431f7e6 100644 --- a/src/test/test-random-util.c +++ b/src/test/test-random-util.c @@ -3,15 +3,16 @@ #include "hexdecoct.h" #include "random-util.h" #include "log.h" +#include "tests.h" -static void test_acquire_random_bytes(bool high_quality_required) { +static void test_genuine_random_bytes(RandomFlags flags) { uint8_t buf[16] = {}; unsigned i; log_info("/* %s */", __func__); for (i = 1; i < sizeof buf; i++) { - assert_se(acquire_random_bytes(buf, i, high_quality_required) == 0); + assert_se(genuine_random_bytes(buf, i, flags) == 0); if (i + 1 < sizeof buf) assert_se(buf[i] == 0); @@ -19,14 +20,14 @@ static void test_acquire_random_bytes(bool high_quality_required) { } } -static void test_pseudorandom_bytes(void) { +static void test_pseudo_random_bytes(void) { uint8_t buf[16] = {}; unsigned i; log_info("/* %s */", __func__); for (i = 1; i < sizeof buf; i++) { - pseudorandom_bytes(buf, i); + pseudo_random_bytes(buf, i); if (i + 1 < sizeof buf) assert_se(buf[i] == 0); @@ -34,15 +35,33 @@ static void test_pseudorandom_bytes(void) { } } +static void test_rdrand(void) { + int r, i; + + for (i = 0; i < 10; i++) { + unsigned long x = 0; + + r = rdrand(&x); + if (r < 0) { + log_error_errno(r, "RDRAND failed: %m"); + return; + } + + printf("%lx\n", x); + } +} + int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); + + test_genuine_random_bytes(RANDOM_EXTEND_WITH_PSEUDO); + test_genuine_random_bytes(0); + test_genuine_random_bytes(RANDOM_BLOCK); + test_genuine_random_bytes(RANDOM_ALLOW_RDRAND); - test_acquire_random_bytes(false); - test_acquire_random_bytes(true); + test_pseudo_random_bytes(); - test_pseudorandom_bytes(); + test_rdrand(); return 0; } diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c index 15701b2712..771719a267 100644 --- a/src/test/test-rlimit-util.c +++ b/src/test/test-rlimit-util.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "capability-util.h" #include "macro.h" +#include "missing.h" #include "rlimit-util.h" #include "string-util.h" #include "util.h" diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index c986284155..1aa178182b 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -19,20 +19,18 @@ int main(int argc, char *argv[]) { Service *ser; int r; + test_setup_logging(LOG_INFO); + r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); /* prepare the test */ - assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(set_unit_path(get_testdata_dir()) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return EXIT_TEST_SKIP; - } + if (MANAGER_SKIP_TEST(r)) + return log_tests_skipped_errno(r, "manager_new"); assert_se(r >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); diff --git a/src/test/test-sd-hwdb.c b/src/test/test-sd-hwdb.c new file mode 100644 index 0000000000..17ca6a0e27 --- /dev/null +++ b/src/test/test-sd-hwdb.c @@ -0,0 +1,74 @@ +#include "sd-hwdb.h" + +#include "alloc-util.h" +#include "errno.h" +#include "tests.h" + +static int test_failed_enumerate(void) { + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + const char *key, *value; + int r; + + log_info("/* %s */", __func__); + + r = sd_hwdb_new(&hwdb); + if (r == -ENOENT) + return r; + assert_se(r == 0); + + assert_se(sd_hwdb_seek(hwdb, "no-such-modalias-should-exist") == 0); + + assert_se(sd_hwdb_enumerate(hwdb, &key, &value) == 0); + assert_se(sd_hwdb_enumerate(hwdb, &key, NULL) == -EINVAL); + assert_se(sd_hwdb_enumerate(hwdb, NULL, &value) == -EINVAL); + + return 0; +} + +#define DELL_MODALIAS \ + "evdev:atkbd:dmi:bvnXXX:bvrYYY:bdZZZ:svnDellXXX:pnYYY" + +static void test_basic_enumerate(void) { + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + const char *key, *value; + size_t len1 = 0, len2 = 0; + int r; + + log_info("/* %s */", __func__); + + assert_se(sd_hwdb_new(&hwdb) == 0); + + assert_se(sd_hwdb_seek(hwdb, DELL_MODALIAS) == 0); + + for (;;) { + r = sd_hwdb_enumerate(hwdb, &key, &value); + assert(IN_SET(r, 0, 1)); + if (r == 0) + break; + assert(key); + assert(value); + log_debug("A: \"%s\" → \"%s\"", key, value); + len1 += strlen(key) + strlen(value); + } + + SD_HWDB_FOREACH_PROPERTY(hwdb, DELL_MODALIAS, key, value) { + log_debug("B: \"%s\" → \"%s\"", key, value); + len2 += strlen(key) + strlen(value); + } + + assert_se(len1 == len2); +} + +int main(int argc, char *argv[]) { + int r; + + test_setup_logging(LOG_DEBUG); + + r = test_failed_enumerate(); + if (r < 0) + return log_tests_skipped_errno(r, "cannot open hwdb"); + + test_basic_enumerate(); + + return 0; +} diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index d82cb5c1c5..fbfeedd536 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -20,6 +20,7 @@ #include "seccomp-util.h" #include "set.h" #include "string-util.h" +#include "tests.h" #include "util.h" #include "virt.h" @@ -35,6 +36,8 @@ static void test_seccomp_arch_to_string(void) { uint32_t a, b; const char *name; + log_info("/* %s */", __func__); + a = seccomp_arch_native(); assert_se(a > 0); name = seccomp_arch_to_string(a); @@ -46,6 +49,8 @@ static void test_seccomp_arch_to_string(void) { static void test_architecture_table(void) { const char *n, *n2; + log_info("/* %s */", __func__); + NULSTR_FOREACH(n, "native\0" "x86\0" @@ -74,6 +79,8 @@ static void test_architecture_table(void) { } static void test_syscall_filter_set_find(void) { + log_info("/* %s */", __func__); + assert_se(!syscall_filter_set_find(NULL)); assert_se(!syscall_filter_set_find("")); assert_se(!syscall_filter_set_find("quux")); @@ -88,10 +95,16 @@ static void test_filter_sets(void) { unsigned i; int r; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { pid_t pid; @@ -104,11 +117,11 @@ static void test_filter_sets(void) { if (pid == 0) { /* Child? */ int fd; - /* if we look at the default set (or one that includes it), whitelist instead of blacklist */ + /* If we look at the default set (or one that includes it), whitelist instead of blacklist */ if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE)) - r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW); + r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true); else - r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN)); + r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true); if (r < 0) _exit(EXIT_FAILURE); @@ -128,11 +141,50 @@ static void test_filter_sets(void) { } } +static void test_filter_sets_ordered(void) { + size_t i; + + log_info("/* %s */", __func__); + + /* Ensure "@default" always remains at the beginning of the list */ + assert_se(SYSCALL_FILTER_SET_DEFAULT == 0); + assert_se(streq(syscall_filter_sets[0].name, "@default")); + + for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { + const char *k, *p = NULL; + + /* Make sure each group has a description */ + assert_se(!isempty(syscall_filter_sets[0].help)); + + /* Make sure the groups are ordered alphabetically, except for the first entry */ + assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0); + + NULSTR_FOREACH(k, syscall_filter_sets[i].value) { + + /* Ensure each syscall list is in itself ordered, but groups before names */ + assert_se(!p || + (*p == '@' && *k != '@') || + (((*p == '@' && *k == '@') || + (*p != '@' && *k != '@')) && + strcmp(p, k) < 0)); + + p = k; + } + } +} + static void test_restrict_namespace(void) { char *s = NULL; unsigned long ul; pid_t pid; + if (!have_namespaces()) { + log_notice("Testing without namespaces, skipping %s", __func__); + return; + } + + log_info("/* %s */", __func__); + assert_se(namespace_flags_to_string(0, &s) == 0 && streq(s, "")); s = mfree(s); assert_se(namespace_flags_to_string(CLONE_NEWNS, &s) == 0 && streq(s, "mnt")); @@ -160,10 +212,14 @@ static void test_restrict_namespace(void) { assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL); s = mfree(s); - if (!is_seccomp_available()) + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping remaining tests in %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping remaining tests in %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -223,13 +279,22 @@ static void test_restrict_namespace(void) { static void test_protect_sysctl(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } - if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */ + /* in containers _sysctl() is likely missing anyway */ + if (detect_container() > 0) { + log_notice("Testing in container, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -256,10 +321,16 @@ static void test_protect_sysctl(void) { static void test_restrict_address_families(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -339,13 +410,22 @@ static void test_restrict_address_families(void) { static void test_restrict_realtime(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } - if (detect_container() > 0) /* in containers RT privs are likely missing anyway */ + /* in containers RT privs are likely missing anyway */ + if (detect_container() > 0) { + log_notice("Testing in container, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -377,10 +457,16 @@ static void test_restrict_realtime(void) { static void test_memory_deny_write_execute_mmap(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -421,10 +507,16 @@ static void test_memory_deny_write_execute_shmat(void) { int shmid; pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } shmid = shmget(IPC_PRIVATE, page_size(), 0); assert_se(shmid >= 0); @@ -467,10 +559,16 @@ static void test_memory_deny_write_execute_shmat(void) { static void test_restrict_archs(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -501,10 +599,16 @@ static void test_restrict_archs(void) { static void test_load_syscall_filter_set_raw(void) { pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } pid = fork(); assert_se(pid >= 0); @@ -515,7 +619,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL, true) >= 0); assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); @@ -526,7 +630,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(-1)) >= 0); #endif - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); assert_se(access("/", F_OK) < 0); assert_se(errno == EUCLEAN); @@ -542,7 +646,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_faccessat + 1), INT_TO_PTR(EILSEQ)) >= 0); #endif - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN), true) >= 0); assert_se(access("/", F_OK) < 0); assert_se(errno == EILSEQ); @@ -558,7 +662,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(-1)) >= 0); #endif - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); assert_se(access("/", F_OK) < 0); assert_se(errno == EILSEQ); @@ -575,7 +679,7 @@ static void test_load_syscall_filter_set_raw(void) { assert_se(hashmap_put(s, UINT32_TO_PTR(__NR_ppoll + 1), INT_TO_PTR(EILSEQ)) >= 0); #endif - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH), true) >= 0); assert_se(access("/", F_OK) < 0); assert_se(errno == EILSEQ); @@ -593,10 +697,16 @@ static void test_lock_personality(void) { unsigned long current; pid_t pid; - if (!is_seccomp_available()) + log_info("/* %s */", __func__); + + if (!is_seccomp_available()) { + log_notice("Seccomp not available, skipping %s", __func__); return; - if (geteuid() != 0) + } + if (geteuid() != 0) { + log_notice("Not root, skipping %s", __func__); return; + } assert_se(opinionated_personality(¤t) >= 0); @@ -636,44 +746,14 @@ static void test_lock_personality(void) { assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS); } -static void test_filter_sets_ordered(void) { - size_t i; - - /* Ensure "@default" always remains at the beginning of the list */ - assert_se(SYSCALL_FILTER_SET_DEFAULT == 0); - assert_se(streq(syscall_filter_sets[0].name, "@default")); - - for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { - const char *k, *p = NULL; - - /* Make sure each group has a description */ - assert_se(!isempty(syscall_filter_sets[0].help)); - - /* Make sure the groups are ordered alphabetically, except for the first entry */ - assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0); - - NULSTR_FOREACH(k, syscall_filter_sets[i].value) { - - /* Ensure each syscall list is in itself ordered, but groups before names */ - assert_se(!p || - (*p == '@' && *k != '@') || - (((*p == '@' && *k == '@') || - (*p != '@' && *k != '@')) && - strcmp(p, k) < 0)); - - p = k; - } - } -} - int main(int argc, char *argv[]) { - - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); test_seccomp_arch_to_string(); test_architecture_table(); test_syscall_filter_set_find(); test_filter_sets(); + test_filter_sets_ordered(); test_restrict_namespace(); test_protect_sysctl(); test_restrict_address_families(); @@ -683,7 +763,6 @@ int main(int argc, char *argv[]) { test_restrict_archs(); test_load_syscall_filter_set_raw(); test_lock_personality(); - test_filter_sets_ordered(); return 0; } diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c index 6caeb843f3..59b4f71946 100644 --- a/src/test/test-selinux.c +++ b/src/test/test-selinux.c @@ -7,6 +7,7 @@ #include "log.h" #include "selinux-util.h" #include "string-util.h" +#include "tests.h" #include "time-util.h" #include "util.h" @@ -92,8 +93,7 @@ int main(int argc, char **argv) { if (argc >= 2) path = argv[1]; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); test_testing(); test_loading(); diff --git a/src/test/test-serialize.c b/src/test/test-serialize.c new file mode 100644 index 0000000000..a57d5db2b1 --- /dev/null +++ b/src/test/test-serialize.c @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "log.h" +#include "serialize.h" +#include "strv.h" +#include "tests.h" +#include "tmpfile-util.h" + +char long_string[LONG_LINE_MAX+1]; + +static void test_serialize_item(void) { + _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + + assert_se(fmkostemp_safe(fn, "r+", &f) == 0); + log_info("/* %s (%s) */", __func__, fn); + + assert_se(serialize_item(f, "a", NULL) == 0); + assert_se(serialize_item(f, "a", "bbb") == 1); + assert_se(serialize_item(f, "a", "bbb") == 1); + assert_se(serialize_item(f, "a", long_string) == -EINVAL); + assert_se(serialize_item(f, long_string, "a") == -EINVAL); + assert_se(serialize_item(f, long_string, long_string) == -EINVAL); + + rewind(f); + + _cleanup_free_ char *line1 = NULL, *line2 = NULL, *line3 = NULL; + assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0); + assert_se(streq(line1, "a=bbb")); + assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0); + assert_se(streq(line2, "a=bbb")); + assert_se(read_line(f, LONG_LINE_MAX, &line3) == 0); + assert_se(streq(line3, "")); +} + +static void test_serialize_item_escaped(void) { + _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + + assert_se(fmkostemp_safe(fn, "r+", &f) == 0); + log_info("/* %s (%s) */", __func__, fn); + + assert_se(serialize_item_escaped(f, "a", NULL) == 0); + assert_se(serialize_item_escaped(f, "a", "bbb") == 1); + assert_se(serialize_item_escaped(f, "a", "bbb") == 1); + assert_se(serialize_item_escaped(f, "a", long_string) == -EINVAL); + assert_se(serialize_item_escaped(f, long_string, "a") == -EINVAL); + assert_se(serialize_item_escaped(f, long_string, long_string) == -EINVAL); + + rewind(f); + + _cleanup_free_ char *line1 = NULL, *line2 = NULL, *line3 = NULL; + assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0); + assert_se(streq(line1, "a=bbb")); + assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0); + assert_se(streq(line2, "a=bbb")); + assert_se(read_line(f, LONG_LINE_MAX, &line3) == 0); + assert_se(streq(line3, "")); +} + +static void test_serialize_usec(void) { + _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + + assert_se(fmkostemp_safe(fn, "r+", &f) == 0); + log_info("/* %s (%s) */", __func__, fn); + + assert_se(serialize_usec(f, "usec1", USEC_INFINITY) == 0); + assert_se(serialize_usec(f, "usec2", 0) == 1); + assert_se(serialize_usec(f, "usec3", USEC_INFINITY-1) == 1); + + rewind(f); + + _cleanup_free_ char *line1 = NULL, *line2 = NULL; + usec_t x; + + assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0); + assert_se(streq(line1, "usec2=0")); + assert_se(deserialize_usec(line1 + 6, &x) == 0); + assert_se(x == 0); + + assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0); + assert_se(startswith(line2, "usec3=")); + assert_se(deserialize_usec(line2 + 6, &x) == 0); + assert_se(x == USEC_INFINITY-1); +} + +static void test_serialize_strv(void) { + _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + + char **strv = STRV_MAKE("a", "b", "foo foo", + "nasty1 \"", + "\"nasty2 ", + "nasty3 '", + "\"nasty4 \"", + "nasty5\n", + "\nnasty5\nfoo=bar", + "\nnasty5\nfoo=bar"); + + assert_se(fmkostemp_safe(fn, "r+", &f) == 0); + log_info("/* %s (%s) */", __func__, fn); + + assert_se(serialize_strv(f, "strv1", NULL) == 0); + assert_se(serialize_strv(f, "strv2", STRV_MAKE_EMPTY) == 0); + assert_se(serialize_strv(f, "strv3", strv) == 1); + assert_se(serialize_strv(f, "strv4", STRV_MAKE(long_string)) == -EINVAL); + + rewind(f); + + _cleanup_strv_free_ char **strv2 = NULL; + for (;;) { + _cleanup_free_ char *line = NULL; + int r; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r == 0) + break; + assert_se(r > 0); + + const char *t = startswith(line, "strv3="); + assert_se(t); + + char *un; + assert_se(cunescape(t, 0, &un) >= 0); + assert_se(strv_consume(&strv2, un) >= 0); + } + + assert_se(strv_equal(strv, strv2)); +} + +static void test_deserialize_environment(void) { + _cleanup_strv_free_ char **env; + + log_info("/* %s */", __func__); + + assert_se(env = strv_new("A=1")); + + assert_se(deserialize_environment("B=2", &env) >= 0); + assert_se(deserialize_environment("FOO%%=a\\177b\\nc\\td e", &env) >= 0); + + assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e"))); + + assert_se(deserialize_environment("foo\\", &env) < 0); + assert_se(deserialize_environment("bar\\_baz", &env) < 0); +} + +static void test_serialize_environment(void) { + _cleanup_strv_free_ char **env = NULL, **env2 = NULL; + _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-env-util.XXXXXXX"; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert_se(fmkostemp_safe(fn, "r+", &f) == 0); + log_info("/* %s (%s) */", __func__, fn); + + assert_se(env = strv_new("A=1", + "B=2", + "C=ąęółń", + "D=D=a\\x0Ab", + "FOO%%=a\177b\nc\td e")); + + assert_se(serialize_strv(f, "env", env) == 1); + assert_se(fflush_and_check(f) == 0); + + rewind(f); + + for (;;) { + _cleanup_free_ char *line = NULL; + const char *l; + + r = read_line(f, LONG_LINE_MAX, &line); + assert_se(r >= 0); + + if (r == 0) + break; + + l = strstrip(line); + + assert_se(startswith(l, "env=")); + + r = deserialize_environment(l+4, &env2); + assert_se(r >= 0); + } + assert_se(feof(f)); + + assert_se(strv_equal(env, env2)); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + memset(long_string, 'x', sizeof(long_string)-1); + char_array_0(long_string); + + test_serialize_item(); + test_serialize_item_escaped(); + test_serialize_usec(); + test_serialize_strv(); + test_deserialize_environment(); + test_serialize_environment(); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-set-disable-mempool.c b/src/test/test-set-disable-mempool.c new file mode 100644 index 0000000000..aea83d2679 --- /dev/null +++ b/src/test/test-set-disable-mempool.c @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <pthread.h> + +#include "process-util.h" +#include "set.h" +#include "tests.h" + +#define NUM 100 + +static void* thread(void *p) { + Set **s = p; + + assert_se(s); + assert_se(*s); + + assert_se(!is_main_thread()); + assert_se(set_size(*s) == NUM); + *s = set_free(*s); + + return NULL; +} + +static void test_one(const char *val) { + pthread_t t; + int x[NUM] = {}; + unsigned i; + Set *s; + + log_info("Testing with SYSTEMD_MEMPOOL=%s", val); + assert_se(setenv("SYSTEMD_MEMPOOL", val, true) == 0); + assert_se(is_main_thread()); + + assert_se(s = set_new(NULL)); + for (i = 0; i < NUM; i++) + assert_se(set_put(s, &x[i])); + + assert_se(pthread_create(&t, NULL, thread, &s) == 0); + assert_se(pthread_join(t, NULL) == 0); + + assert_se(!s); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_one("0"); + /* The value $SYSTEMD_MEMPOOL= is cached. So the following + * test should also succeed. */ + test_one("1"); + + return 0; +} diff --git a/src/test/test-set.c b/src/test/test-set.c index 6307403e4c..340edeb65f 100644 --- a/src/test/test-set.c +++ b/src/test/test-set.c @@ -45,6 +45,24 @@ static void test_set_free_with_destructor(void) { assert_se(items[3].seen == 0); } +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_hash_ops, void, trivial_hash_func, trivial_compare_func, Item, item_seen); + +static void test_set_free_with_hash_ops(void) { + Set *m; + struct Item items[4] = {}; + unsigned i; + + assert_se(m = set_new(&item_hash_ops)); + for (i = 0; i < ELEMENTSOF(items) - 1; i++) + assert_se(set_put(m, items + i) == 1); + + m = set_free(m); + assert_se(items[0].seen == 1); + assert_se(items[1].seen == 1); + assert_se(items[2].seen == 1); + assert_se(items[3].seen == 0); +} + static void test_set_put(void) { _cleanup_set_free_ Set *m = NULL; @@ -64,6 +82,7 @@ static void test_set_put(void) { int main(int argc, const char *argv[]) { test_set_steal_first(); test_set_free_with_destructor(); + test_set_free_with_hash_ops(); test_set_put(); return 0; diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c index c9343364d4..d2666dd1d8 100644 --- a/src/test/test-sigbus.c +++ b/src/test/test-sigbus.c @@ -2,12 +2,14 @@ #include <sys/mman.h> +#if HAVE_VALGRIND_VALGRIND_H +# include <valgrind/valgrind.h> +#endif + #include "fd-util.h" #include "sigbus.h" +#include "tests.h" #include "util.h" -#if HAVE_VALGRIND_VALGRIND_H -#include <valgrind/valgrind.h> -#endif int main(int argc, char *argv[]) { _cleanup_close_ int fd = -1; @@ -15,14 +17,16 @@ int main(int argc, char *argv[]) { void *addr = NULL; uint8_t *p; + test_setup_logging(LOG_INFO); + +#if HAS_FEATURE_ADDRESS_SANITIZER + return log_tests_skipped("address-sanitizer is enabled"); +#endif #if HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) - return EXIT_TEST_SKIP; + return log_tests_skipped("This test cannot run on valgrind"); #endif -#ifdef __SANITIZE_ADDRESS__ - return EXIT_TEST_SKIP; -#endif sigbus_install(); assert_se(sigbus_pop(&addr) == 0); diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index 5286442e26..2a6d5e765a 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <inttypes.h> #include <linux/fiemap.h> #include <stdio.h> @@ -7,13 +8,16 @@ #include "log.h" #include "sleep-config.h" #include "strv.h" +#include "tests.h" #include "util.h" static void test_parse_sleep_config(void) { const char *verb; + log_info("/* %s */", __func__); + FOREACH_STRING(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate") - assert_se(parse_sleep_config(verb, NULL, NULL, NULL) == 0); + assert_se(parse_sleep_config(verb, NULL, NULL, NULL, NULL) == 0); } static int test_fiemap(const char *path) { @@ -21,42 +25,44 @@ static int test_fiemap(const char *path) { _cleanup_close_ int fd = -1; int r; + log_info("/* %s */", __func__); + fd = open(path, O_RDONLY | O_CLOEXEC | O_NONBLOCK); if (fd < 0) return log_error_errno(errno, "failed to open %s: %m", path); r = read_fiemap(fd, &fiemap); - if (r == -EOPNOTSUPP) { - log_info("Skipping test, not supported"); - exit(EXIT_TEST_SKIP); - } + if (r == -EOPNOTSUPP) + exit(log_tests_skipped("Not supported")); if (r < 0) return log_error_errno(r, "Unable to read extent map for '%s': %m", path); log_info("extent map information for %s:", path); - log_info("\t start: %llu", fiemap->fm_start); - log_info("\t length: %llu", fiemap->fm_length); - log_info("\t flags: %u", fiemap->fm_flags); - log_info("\t number of mapped extents: %u", fiemap->fm_mapped_extents); - log_info("\t extent count: %u", fiemap->fm_extent_count); + log_info("\t start: %" PRIu64, (uint64_t) fiemap->fm_start); + log_info("\t length: %" PRIu64, (uint64_t) fiemap->fm_length); + log_info("\t flags: %" PRIu32, fiemap->fm_flags); + log_info("\t number of mapped extents: %" PRIu32, fiemap->fm_mapped_extents); + log_info("\t extent count: %" PRIu32, fiemap->fm_extent_count); if (fiemap->fm_extent_count > 0) - log_info("\t first extent location: %llu", - fiemap->fm_extents[0].fe_physical / page_size()); + log_info("\t first extent location: %" PRIu64, + (uint64_t) (fiemap->fm_extents[0].fe_physical / page_size())); return 0; } static void test_sleep(void) { _cleanup_strv_free_ char - **standby = strv_new("standby", NULL), - **mem = strv_new("mem", NULL), - **disk = strv_new("disk", NULL), - **suspend = strv_new("suspend", NULL), - **reboot = strv_new("reboot", NULL), - **platform = strv_new("platform", NULL), - **shutdown = strv_new("shutdown", NULL), - **freez = strv_new("freeze", NULL); + **standby = strv_new("standby"), + **mem = strv_new("mem"), + **disk = strv_new("disk"), + **suspend = strv_new("suspend"), + **reboot = strv_new("reboot"), + **platform = strv_new("platform"), + **shutdown = strv_new("shutdown"), + **freez = strv_new("freeze"); int r; - log_info("/* configuration */"); + log_info("/* %s */", __func__); + + log_info("/= configuration =/"); log_info("Standby configured: %s", yes_no(can_sleep_state(standby) > 0)); log_info("Suspend configured: %s", yes_no(can_sleep_state(mem) > 0)); log_info("Hibernate configured: %s", yes_no(can_sleep_state(disk) > 0)); @@ -66,7 +72,7 @@ static void test_sleep(void) { log_info("Hibernate+Shutdown configured: %s", yes_no(can_sleep_disk(shutdown) > 0)); log_info("Freeze configured: %s", yes_no(can_sleep_state(freez) > 0)); - log_info("/* running system */"); + log_info("/= running system =/"); r = can_sleep("suspend"); log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror(-r)); r = can_sleep("hibernate"); @@ -80,8 +86,7 @@ static void test_sleep(void) { int main(int argc, char* argv[]) { int i, r = 0, k; - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); if (getuid() != 0) log_warning("This program is unlikely to work for unprivileged users"); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index ac2ea52a5c..07ff487834 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -6,16 +6,24 @@ #include "alloc-util.h" #include "async.h" +#include "escape.h" +#include "exit-status.h" #include "fd-util.h" #include "in-addr-util.h" +#include "io-util.h" #include "log.h" #include "macro.h" +#include "missing_network.h" #include "process-util.h" #include "socket-util.h" #include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" #include "util.h" static void test_ifname_valid(void) { + log_info("/* %s */", __func__); + assert(ifname_valid("foo")); assert(ifname_valid("eth0")); @@ -38,61 +46,121 @@ static void test_ifname_valid(void) { assert(!ifname_valid("xxxxxxxxxxxxxxxx")); } -static void test_socket_address_parse(void) { +static void test_socket_address_parse_one(const char *in, int ret, int family, const char *expected) { SocketAddress a; + _cleanup_free_ char *out = NULL; + int r; + + r = socket_address_parse(&a, in); + if (r >= 0) + assert_se(socket_address_print(&a, &out) >= 0); + + log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in, + r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); + assert_se(r == ret); + if (r >= 0) { + assert_se(a.sockaddr.sa.sa_family == family); + assert_se(streq(out, expected ?: in)); + } +} + +#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path)) +assert_cc(sizeof(((struct sockaddr_un){}).sun_path) == 108); - assert_se(socket_address_parse(&a, "junk") < 0); - assert_se(socket_address_parse(&a, "192.168.1.1") < 0); - assert_se(socket_address_parse(&a, ".168.1.1") < 0); - assert_se(socket_address_parse(&a, "989.168.1.1") < 0); - assert_se(socket_address_parse(&a, "192.168.1.1:65536") < 0); - assert_se(socket_address_parse(&a, "192.168.1.1:0") < 0); - assert_se(socket_address_parse(&a, "0") < 0); - assert_se(socket_address_parse(&a, "65536") < 0); +static void test_socket_address_parse(void) { + log_info("/* %s */", __func__); + + test_socket_address_parse_one("junk", -EINVAL, 0, NULL); + test_socket_address_parse_one("192.168.1.1", -EINVAL, 0, NULL); + test_socket_address_parse_one(".168.1.1", -EINVAL, 0, NULL); + test_socket_address_parse_one("989.168.1.1", -EINVAL, 0, NULL); + test_socket_address_parse_one("192.168.1.1:65536", -ERANGE, 0, NULL); + test_socket_address_parse_one("192.168.1.1:0", -EINVAL, 0, NULL); + test_socket_address_parse_one("0", -EINVAL, 0, NULL); + test_socket_address_parse_one("65536", -ERANGE, 0, NULL); - assert_se(socket_address_parse(&a, "65535") >= 0); + const int default_family = socket_ipv6_is_supported() ? AF_INET6 : AF_INET; + + test_socket_address_parse_one("65535", 0, default_family, "[::]:65535"); /* The checks below will pass even if ipv6 is disabled in * kernel. The underlying glibc's inet_pton() is just a string * parser and doesn't make any syscalls. */ - assert_se(socket_address_parse(&a, "[::1]") < 0); - assert_se(socket_address_parse(&a, "[::1]8888") < 0); - assert_se(socket_address_parse(&a, "::1") < 0); - assert_se(socket_address_parse(&a, "[::1]:0") < 0); - assert_se(socket_address_parse(&a, "[::1]:65536") < 0); - assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); + test_socket_address_parse_one("[::1]", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]8888", -EINVAL, 0, NULL); + test_socket_address_parse_one("::1", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL); + test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL); + test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL); - assert_se(socket_address_parse(&a, "8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET)); + test_socket_address_parse_one("8888", 0, default_family, "[::]:8888"); + test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6, + "[2001:db8:0:85a3::ac1f:8001]:8888"); + test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL); + test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL); + test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL); + test_socket_address_parse_one("/", 0, AF_UNIX, NULL); + test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL); - assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + { + char aaa[SUN_PATH_LEN + 1] = "@"; - assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + memset(aaa + 1, 'a', SUN_PATH_LEN - 1); + char_array_0(aaa); - assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET); + test_socket_address_parse_one(aaa, -EINVAL, 0, NULL); - assert_se(socket_address_parse(&a, "/foo/bar") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_UNIX); + aaa[SUN_PATH_LEN - 1] = '\0'; + test_socket_address_parse_one(aaa, 0, AF_UNIX, NULL); + } - assert_se(socket_address_parse(&a, "@abstract") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_UNIX); + test_socket_address_parse_one("vsock:2:1234", 0, AF_VSOCK, NULL); + test_socket_address_parse_one("vsock::1234", 0, AF_VSOCK, NULL); + test_socket_address_parse_one("vsock:2:1234x", -EINVAL, 0, NULL); + test_socket_address_parse_one("vsock:2x:1234", -EINVAL, 0, NULL); + test_socket_address_parse_one("vsock:2", -EINVAL, 0, NULL); +} - assert_se(socket_address_parse(&a, "vsock::1234") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_VSOCK); - assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_VSOCK); - assert_se(socket_address_parse(&a, "vsock:2:1234x") < 0); - assert_se(socket_address_parse(&a, "vsock:2x:1234") < 0); - assert_se(socket_address_parse(&a, "vsock:2") < 0); +static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) { + _cleanup_free_ char *out = NULL, *c = NULL; + + SocketAddress a = { .sockaddr = { .un = { .sun_family = AF_UNIX } }, + .size = offsetof(struct sockaddr_un, sun_path) + len_in, + .type = SOCK_STREAM, + }; + memcpy(a.sockaddr.un.sun_path, in, len_in); + + assert_se(socket_address_print(&a, &out) >= 0); + assert_se(c = cescape(in)); + log_info("\"%s\" → \"%s\" (expect \"%s\")", in, out, expected); + assert_se(streq(out, expected)); +} + +static void test_socket_print_unix(void) { + log_info("/* %s */", __func__); + + /* Some additional tests for abstract addresses which we don't parse */ + + test_socket_print_unix_one("\0\0\0\0", 4, "@\\000\\000\\000"); + test_socket_print_unix_one("@abs", 5, "@abs"); + test_socket_print_unix_one("\n", 2, "\\n"); + test_socket_print_unix_one("", 1, "<unnamed>"); + test_socket_print_unix_one("\0", 1, "<unnamed>"); + test_socket_print_unix_one("\0_________________________there's 108 characters in this string_____________________________________________", 108, + "@_________________________there\\'s 108 characters in this string_____________________________________________"); + test_socket_print_unix_one("////////////////////////////////////////////////////////////////////////////////////////////////////////////", 108, + "////////////////////////////////////////////////////////////////////////////////////////////////////////////"); + test_socket_print_unix_one("////////////////////////////////////////////////////////////////////////////////////////////////////////////", 109, + "////////////////////////////////////////////////////////////////////////////////////////////////////////////"); + test_socket_print_unix_one("\0\a\b\n\255", 6, "@\\a\\b\\n\\255\\000"); } static void test_socket_address_parse_netlink(void) { SocketAddress a; + log_info("/* %s */", __func__); + assert_se(socket_address_parse_netlink(&a, "junk") < 0); assert_se(socket_address_parse_netlink(&a, "") < 0); @@ -116,8 +184,9 @@ static void test_socket_address_parse_netlink(void) { } static void test_socket_address_equal(void) { - SocketAddress a; - SocketAddress b; + SocketAddress a, b; + + log_info("/* %s */", __func__); assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); assert_se(socket_address_parse(&b, "192.168.1.1:888") >= 0); @@ -167,6 +236,8 @@ static void test_socket_address_equal(void) { static void test_socket_address_get_path(void) { SocketAddress a; + log_info("/* %s */", __func__); + assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); assert_se(!socket_address_get_path(&a)); @@ -186,6 +257,8 @@ static void test_socket_address_get_path(void) { static void test_socket_address_is(void) { SocketAddress a; + log_info("/* %s */", __func__); + assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM)); assert_se(!socket_address_is(&a, "route", SOCK_STREAM)); @@ -195,6 +268,8 @@ static void test_socket_address_is(void) { static void test_socket_address_is_netlink(void) { SocketAddress a; + log_info("/* %s */", __func__); + assert_se(socket_address_parse_netlink(&a, "route 10") >= 0); assert_se(socket_address_is_netlink(&a, "route 10")); assert_se(!socket_address_is_netlink(&a, "192.168.1.1:8888")); @@ -202,9 +277,10 @@ static void test_socket_address_is_netlink(void) { } static void test_in_addr_is_null(void) { - union in_addr_union i = {}; + log_info("/* %s */", __func__); + assert_se(in_addr_is_null(AF_INET, &i) == true); assert_se(in_addr_is_null(AF_INET6, &i) == true); @@ -225,6 +301,7 @@ static void test_in_addr_prefix_intersect_one(unsigned f, const char *a, unsigne } static void test_in_addr_prefix_intersect(void) { + log_info("/* %s */", __func__); test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 32, "255.255.255.254", 32, 0); test_in_addr_prefix_intersect_one(AF_INET, "255.255.255.255", 0, "255.255.255.255", 32, 1); @@ -266,6 +343,7 @@ static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigne } static void test_in_addr_prefix_next(void) { + log_info("/* %s */", __func__); test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0"); test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0"); @@ -285,7 +363,6 @@ static void test_in_addr_prefix_next(void) { test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, NULL); test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120, NULL); - } static void test_in_addr_to_string_one(int f, const char *addr) { @@ -299,6 +376,8 @@ static void test_in_addr_to_string_one(int f, const char *addr) { } static void test_in_addr_to_string(void) { + log_info("/* %s */", __func__); + test_in_addr_to_string_one(AF_INET, "192.168.0.1"); test_in_addr_to_string_one(AF_INET, "10.11.12.13"); test_in_addr_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); @@ -323,6 +402,8 @@ static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex } static void test_in_addr_ifindex_to_string(void) { + log_info("/* %s */", __func__); + test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1"); test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13"); test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); @@ -338,6 +419,7 @@ static void test_in_addr_ifindex_from_string_auto(void) { int family, ifindex; union in_addr_union ua; + log_info("/* %s */", __func__); /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */ assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0); @@ -381,6 +463,9 @@ static void test_sockaddr_equal(void) { .vm.svm_port = 0, .vm.svm_cid = VMADDR_CID_ANY, }; + + log_info("/* %s */", __func__); + assert_se(sockaddr_equal(&a, &a)); assert_se(sockaddr_equal(&a, &b)); assert_se(sockaddr_equal(&d, &d)); @@ -391,6 +476,8 @@ static void test_sockaddr_equal(void) { } static void test_sockaddr_un_len(void) { + log_info("/* %s */", __func__); + static const struct sockaddr_un fs = { .sun_family = AF_UNIX, .sun_path = "/foo/bar/waldo", @@ -401,7 +488,7 @@ static void test_sockaddr_un_len(void) { .sun_path = "\0foobar", }; - assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path)); + assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path) + 1); assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1)); } @@ -409,6 +496,8 @@ static void test_in_addr_is_multicast(void) { union in_addr_union a, b; int f; + log_info("/* %s */", __func__); + assert_se(in_addr_from_string_auto("192.168.3.11", &f, &a) >= 0); assert_se(in_addr_is_multicast(f, &a) == 0); @@ -425,13 +514,14 @@ static void test_in_addr_is_multicast(void) { static void test_getpeercred_getpeergroups(void) { int r; + log_info("/* %s */", __func__); + r = safe_fork("(getpeercred)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); assert_se(r >= 0); if (r == 0) { static const gid_t gids[] = { 3, 4, 5, 6, 7 }; gid_t *test_gids; - _cleanup_free_ gid_t *peer_groups = NULL; size_t n_test_gids; uid_t test_uid; gid_t test_gid; @@ -472,25 +562,245 @@ static void test_getpeercred_getpeergroups(void) { assert_se(ucred.gid == test_gid); assert_se(ucred.pid == getpid_cached()); - r = getpeergroups(pair[0], &peer_groups); - assert_se(r >= 0 || IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)); + { + _cleanup_free_ gid_t *peer_groups = NULL; - if (r >= 0) { - assert_se((size_t) r == n_test_gids); - assert_se(memcmp(peer_groups, test_gids, sizeof(gid_t) * n_test_gids) == 0); + r = getpeergroups(pair[0], &peer_groups); + assert_se(r >= 0 || IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)); + + if (r >= 0) { + assert_se((size_t) r == n_test_gids); + assert_se(memcmp(peer_groups, test_gids, sizeof(gid_t) * n_test_gids) == 0); + } } safe_close_pair(pair); + _exit(EXIT_SUCCESS); } } -int main(int argc, char *argv[]) { +static void test_passfd_read(void) { + static const char file_contents[] = "test contents for passfd"; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; + + log_info("/* %s */", __func__); + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(passfd_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX"; + _cleanup_close_ int tmpfd = -1; + + pair[0] = safe_close(pair[0]); + + tmpfd = mkostemp_safe(tmpfile); + assert_se(tmpfd >= 0); + assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); + tmpfd = safe_close(tmpfd); + + tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + + assert_se(send_one_fd(pair[1], tmpfd, MSG_DONTWAIT) == 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + _cleanup_close_ int fd = -1; + + pair[1] = safe_close(pair[1]); + + assert_se(receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd) == 0); + + assert_se(fd >= 0); + r = read(fd, buf, sizeof(buf)-1); + assert_se(r >= 0); + buf[r] = 0; + assert_se(streq(buf, file_contents)); +} + +static void test_passfd_contents_read(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + static const char file_contents[] = "test contents in the file"; + static const char wire_contents[] = "test contents on the wire"; + int r; + + log_info("/* %s */", __func__); + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(passfd_contents_read)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(wire_contents); + char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX"; + _cleanup_close_ int tmpfd = -1; + + pair[0] = safe_close(pair[0]); + + tmpfd = mkostemp_safe(tmpfile); + assert_se(tmpfd >= 0); + assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents)); + tmpfd = safe_close(tmpfd); + + tmpfd = open(tmpfile, O_RDONLY); + assert_se(tmpfd >= 0); + assert_se(unlink(tmpfile) == 0); + + assert_se(send_one_fd_iov(pair[1], tmpfd, &iov, 1, MSG_DONTWAIT) > 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + _cleanup_close_ int fd = -1; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + assert_se(k > 0); + buf[k] = 0; + assert_se(streq(buf, wire_contents)); + + assert_se(fd >= 0); + r = read(fd, buf, sizeof(buf)-1); + assert_se(r >= 0); + buf[r] = 0; + assert_se(streq(buf, file_contents)); +} + +static void test_receive_nopassfd(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + static const char wire_contents[] = "no fd passed here"; + int r; + + log_info("/* %s */", __func__); + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(receive_nopassfd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(wire_contents); + + pair[0] = safe_close(pair[0]); + + assert_se(send_one_fd_iov(pair[1], -1, &iov, 1, MSG_DONTWAIT) > 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + assert_se(k > 0); + buf[k] = 0; + assert_se(streq(buf, wire_contents)); + + /* no fd passed here, confirm it was reset */ + assert_se(fd == -1); +} + +static void test_send_nodata_nofd(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; - log_set_max_level(LOG_DEBUG); + log_info("/* %s */", __func__); + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(send_nodata_nofd)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + pair[0] = safe_close(pair[0]); + + assert_se(send_one_fd_iov(pair[1], -1, NULL, 0, MSG_DONTWAIT) == -EINVAL); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + /* recvmsg() will return errno EAGAIN if nothing was sent */ + assert_se(k == -EAGAIN); + + /* receive_one_fd_iov returned error, so confirm &fd wasn't touched */ + assert_se(fd == -999); +} + +static void test_send_emptydata(void) { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + int r; + + log_info("/* %s */", __func__); + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) >= 0); + + r = safe_fork("(send_emptydata)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + assert_se(r >= 0); + + if (r == 0) { + /* Child */ + struct iovec iov = IOVEC_INIT_STRING(""); /* zero-length iov */ + assert_se(iov.iov_len == 0); + + pair[0] = safe_close(pair[0]); + + /* This will succeed, since iov is set. */ + assert_se(send_one_fd_iov(pair[1], -1, &iov, 1, MSG_DONTWAIT) == 0); + _exit(EXIT_SUCCESS); + } + + /* Parent */ + char buf[64]; + struct iovec iov = IOVEC_INIT(buf, sizeof(buf)-1); + int fd = -999; + ssize_t k; + + pair[1] = safe_close(pair[1]); + + k = receive_one_fd_iov(pair[0], &iov, 1, MSG_DONTWAIT, &fd); + /* receive_one_fd_iov() returns -EIO if an fd is not found and no data was returned. */ + assert_se(k == -EIO); + + /* receive_one_fd_iov returned error, so confirm &fd wasn't touched */ + assert_se(fd == -999); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); test_ifname_valid(); test_socket_address_parse(); + test_socket_print_unix(); test_socket_address_parse_netlink(); test_socket_address_equal(); test_socket_address_get_path(); @@ -512,5 +822,11 @@ int main(int argc, char *argv[]) { test_getpeercred_getpeergroups(); + test_passfd_read(); + test_passfd_contents_read(); + test_receive_nopassfd(); + test_send_nodata_nofd(); + test_send_emptydata(); + return 0; } diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index 9c7c352b51..a0ffdf6cb6 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -5,6 +5,7 @@ #include "specifier.h" #include "string-util.h" #include "strv.h" +#include "tests.h" static void test_specifier_escape_one(const char *a, const char *b) { _cleanup_free_ char *x = NULL; @@ -39,7 +40,7 @@ static void test_specifier_escape_strv(void) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); + test_setup_logging(LOG_DEBUG); test_specifier_escape(); test_specifier_escape_strv(); diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 39a7c499b3..4637a7f727 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -6,17 +6,18 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" #include "hexdecoct.h" #include "io-util.h" #include "macro.h" #include "path-util.h" #include "rm-rf.h" #include "missing.h" -#include "mount-util.h" +#include "mountpoint-util.h" +#include "path-util.h" #include "stat-util.h" #include "stdio-util.h" #include "string-util.h" +#include "tmpfile-util.h" static void test_files_same(void) { _cleanup_close_ int fd = -1; @@ -73,11 +74,101 @@ static void test_path_is_temporary_fs(void) { assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); } +static void test_fd_is_network_ns(void) { + _cleanup_close_ int fd = -1; + assert_se(fd_is_network_ns(STDIN_FILENO) == 0); + assert_se(fd_is_network_ns(STDERR_FILENO) == 0); + assert_se(fd_is_network_ns(STDOUT_FILENO) == 0); + + assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0); + assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN)); + fd = safe_close(fd); + + assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); + assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN)); +} + +static void test_device_major_minor_valid(void) { + /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */ + assert_cc(sizeof(dev_t) == sizeof(uint64_t)); + + assert_se(DEVICE_MAJOR_VALID(0U)); + assert_se(DEVICE_MINOR_VALID(0U)); + + assert_se(DEVICE_MAJOR_VALID(1U)); + assert_se(DEVICE_MINOR_VALID(1U)); + + assert_se(!DEVICE_MAJOR_VALID(-1U)); + assert_se(!DEVICE_MINOR_VALID(-1U)); + + assert_se(DEVICE_MAJOR_VALID(1U << 10)); + assert_se(DEVICE_MINOR_VALID(1U << 10)); + + assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1)); + assert_se(DEVICE_MINOR_VALID((1U << 20) - 1)); + + assert_se(!DEVICE_MAJOR_VALID((1U << 12))); + assert_se(!DEVICE_MINOR_VALID((1U << 20))); + + assert_se(!DEVICE_MAJOR_VALID(1U << 25)); + assert_se(!DEVICE_MINOR_VALID(1U << 25)); + + assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX)); + assert_se(!DEVICE_MINOR_VALID(UINT32_MAX)); + + assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX)); + assert_se(!DEVICE_MINOR_VALID(UINT64_MAX)); + + assert_se(DEVICE_MAJOR_VALID(major(0))); + assert_se(DEVICE_MINOR_VALID(minor(0))); +} + +static void test_device_path_make_canonical_one(const char *path) { + _cleanup_free_ char *resolved = NULL, *raw = NULL; + struct stat st; + dev_t devno; + mode_t mode; + int r; + + assert_se(stat(path, &st) >= 0); + r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved); + if (r == -ENOENT) /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we + * run in a container or so? */ + return; + + assert_se(r >= 0); + assert_se(path_equal(path, resolved)); + + assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0); + assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0); + + assert_se(st.st_rdev == devno); + assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT)); +} + +static void test_device_path_make_canonical(void) { + + test_device_path_make_canonical_one("/dev/null"); + test_device_path_make_canonical_one("/dev/zero"); + test_device_path_make_canonical_one("/dev/full"); + test_device_path_make_canonical_one("/dev/random"); + test_device_path_make_canonical_one("/dev/urandom"); + test_device_path_make_canonical_one("/dev/tty"); + + if (is_device_node("/run/systemd/inaccessible/chr") > 0) { + test_device_path_make_canonical_one("/run/systemd/inaccessible/chr"); + test_device_path_make_canonical_one("/run/systemd/inaccessible/blk"); + } +} + int main(int argc, char *argv[]) { test_files_same(); test_is_symlink(); test_path_is_fs_type(); test_path_is_temporary_fs(); + test_fd_is_network_ns(); + test_device_major_minor_valid(); + test_device_path_make_canonical(); return 0; } diff --git a/src/test/test-static-destruct.c b/src/test/test-static-destruct.c new file mode 100644 index 0000000000..eb0523d87a --- /dev/null +++ b/src/test/test-static-destruct.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "alloc-util.h" +#include "static-destruct.h" +#include "tests.h" + +static int foo = 0; +static int bar = 0; +static int baz = 0; +static char* memory = NULL; + +static void test_destroy(int *b) { + (*b)++; +} + +STATIC_DESTRUCTOR_REGISTER(foo, test_destroy); +STATIC_DESTRUCTOR_REGISTER(bar, test_destroy); +STATIC_DESTRUCTOR_REGISTER(bar, test_destroy); +STATIC_DESTRUCTOR_REGISTER(baz, test_destroy); +STATIC_DESTRUCTOR_REGISTER(baz, test_destroy); +STATIC_DESTRUCTOR_REGISTER(baz, test_destroy); +STATIC_DESTRUCTOR_REGISTER(memory, freep); + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + assert_se(memory = strdup("hallo")); + + assert_se(foo == 0 && bar == 0 && baz == 0); + static_destruct(); + assert_se(foo == 1 && bar == 2 && baz == 3); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 3e72ce2c0a..8c1f91d4ef 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -5,6 +5,7 @@ #include "macro.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "utf8.h" static void test_string_erase(void) { @@ -30,6 +31,64 @@ static void test_string_erase(void) { assert_se(x[9] == '\0'); } +static void test_free_and_strndup_one(char **t, const char *src, size_t l, const char *expected, bool change) { + int r; + + log_debug("%s: \"%s\", \"%s\", %zd (expect \"%s\", %s)", + __func__, strnull(*t), strnull(src), l, strnull(expected), yes_no(change)); + + r = free_and_strndup(t, src, l); + assert_se(streq_ptr(*t, expected)); + assert_se(r == change); /* check that change occurs only when necessary */ +} + +static void test_free_and_strndup(void) { + static const struct test_case { + const char *src; + size_t len; + const char *expected; + } cases[] = { + {"abc", 0, ""}, + {"abc", 0, ""}, + {"abc", 1, "a"}, + {"abc", 2, "ab"}, + {"abc", 3, "abc"}, + {"abc", 4, "abc"}, + {"abc", 5, "abc"}, + {"abc", 5, "abc"}, + {"abc", 4, "abc"}, + {"abc", 3, "abc"}, + {"abc", 2, "ab"}, + {"abc", 1, "a"}, + {"abc", 0, ""}, + + {"", 0, ""}, + {"", 1, ""}, + {"", 2, ""}, + {"", 0, ""}, + {"", 1, ""}, + {"", 2, ""}, + {"", 2, ""}, + {"", 1, ""}, + {"", 0, ""}, + + {NULL, 0, NULL}, + + {"foo", 3, "foo"}, + {"foobar", 6, "foobar"}, + }; + + _cleanup_free_ char *t = NULL; + const char *prev_expected = t; + + for (unsigned i = 0; i < ELEMENTSOF(cases); i++) { + test_free_and_strndup_one(&t, + cases[i].src, cases[i].len, cases[i].expected, + !streq_ptr(cases[i].expected, prev_expected)); + prev_expected = t; + } +} + static void test_ascii_strcasecmp_n(void) { assert_se(ascii_strcasecmp_n("", "", 0) == 0); @@ -496,8 +555,34 @@ static void test_memory_startswith(void) { assert_se(!memory_startswith("xxx", 4, "xxxx")); } +static void test_memory_startswith_no_case(void) { + assert_se(streq(memory_startswith_no_case("", 0, ""), "")); + assert_se(streq(memory_startswith_no_case("", 1, ""), "")); + assert_se(streq(memory_startswith_no_case("x", 2, ""), "x")); + assert_se(streq(memory_startswith_no_case("X", 2, ""), "X")); + assert_se(!memory_startswith_no_case("", 1, "X")); + assert_se(!memory_startswith_no_case("", 1, "xxxxXXXX")); + assert_se(streq(memory_startswith_no_case("xxx", 4, "X"), "xx")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "x"), "XX")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "X"), "XX")); + assert_se(streq(memory_startswith_no_case("xxx", 4, "XX"), "x")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "xx"), "X")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "XX"), "X")); + assert_se(streq(memory_startswith_no_case("xxx", 4, "XXX"), "")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "xxx"), "")); + assert_se(streq(memory_startswith_no_case("XXX", 4, "XXX"), "")); + + assert_se(memory_startswith_no_case((char[2]){'x', 'x'}, 2, "xx")); + assert_se(memory_startswith_no_case((char[2]){'x', 'X'}, 2, "xX")); + assert_se(memory_startswith_no_case((char[2]){'X', 'x'}, 2, "Xx")); + assert_se(memory_startswith_no_case((char[2]){'X', 'X'}, 2, "XX")); +} + int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + test_string_erase(); + test_free_and_strndup(); test_ascii_strcasecmp_n(); test_ascii_strcasecmp_nn(); test_cellescape(); @@ -525,6 +610,7 @@ int main(int argc, char *argv[]) { test_first_word(); test_strlen_ptr(); test_memory_startswith(); + test_memory_startswith_no_case(); return 0; } diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c index 362f862221..fae384ef9b 100644 --- a/src/test/test-strip-tab-ansi.c +++ b/src/test/test-strip-tab-ansi.c @@ -3,6 +3,7 @@ #include <stdio.h> #include "alloc-util.h" +#include "pretty-print.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 1c192239a2..31ef1abb44 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -56,6 +56,20 @@ static void test_strptr_in_set(void) { assert_se(!STRPTR_IN_SET(NULL, NULL)); } +static void test_startswith_set(void) { + assert_se(!STARTSWITH_SET("foo", "bar", "baz", "waldo")); + assert_se(!STARTSWITH_SET("foo", "bar")); + + assert_se(STARTSWITH_SET("abc", "a", "ab", "abc")); + assert_se(STARTSWITH_SET("abc", "ax", "ab", "abc")); + assert_se(STARTSWITH_SET("abc", "ax", "abx", "abc")); + assert_se(!STARTSWITH_SET("abc", "ax", "abx", "abcx")); + + assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "foo", "zzz"), "bar")); + assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "", "zzz"), "foobar")); + assert_se(streq_ptr(STARTSWITH_SET("", "hhh", "kkk", "zzz", ""), "")); +} + static const char* const input_table_multiple[] = { "one", "two", @@ -63,6 +77,13 @@ static const char* const input_table_multiple[] = { NULL, }; +static const char* const input_table_quoted[] = { + "one", + " two\t three ", + " four five", + NULL, +}; + static const char* const input_table_one[] = { "one", NULL, @@ -144,6 +165,38 @@ static void test_strv_join(void) { assert_se(streq(w, "")); } +static void test_strv_join_prefix(void) { + _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; + + p = strv_join_prefix((char **)input_table_multiple, ", ", "foo"); + assert_se(p); + assert_se(streq(p, "fooone, footwo, foothree")); + + q = strv_join_prefix((char **)input_table_multiple, ";", "foo"); + assert_se(q); + assert_se(streq(q, "fooone;footwo;foothree")); + + r = strv_join_prefix((char **)input_table_multiple, NULL, "foo"); + assert_se(r); + assert_se(streq(r, "fooone footwo foothree")); + + s = strv_join_prefix((char **)input_table_one, ", ", "foo"); + assert_se(s); + assert_se(streq(s, "fooone")); + + t = strv_join_prefix((char **)input_table_none, ", ", "foo"); + assert_se(t); + assert_se(streq(t, "")); + + v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo"); + assert_se(v); + assert_se(streq(v, "foo, foo")); + + w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo"); + assert_se(w); + assert_se(streq(w, "foo")); +} + static void test_strv_unquote(const char *quoted, char **list) { _cleanup_strv_free_ char **s; _cleanup_free_ char *j; @@ -174,18 +227,127 @@ static void test_invalid_unquote(const char *quoted) { } static void test_strv_split(void) { - char **s; - unsigned i = 0; _cleanup_strv_free_ char **l = NULL; const char str[] = "one,two,three"; l = strv_split(str, ","); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_multiple)); + + strv_free(l); + l = strv_split(" one two\t three", WHITESPACE); assert_se(l); + assert_se(strv_equal(l, (char**) input_table_multiple)); - STRV_FOREACH(s, l) { - assert_se(streq(*s, input_table_multiple[i++])); - } + strv_free(l); + + /* Setting NULL for separator is equivalent to WHITESPACE */ + l = strv_split(" one two\t three", NULL); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_multiple)); + + strv_free(l); + + l = strv_split_full(" one two\t three", NULL, 0); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_multiple)); + + strv_free(l); + + l = strv_split_full(" 'one' \" two\t three \" ' four five'", NULL, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_quoted)); + + strv_free(l); + + /* missing last quote ignores the last element. */ + l = strv_split_full(" 'one' \" two\t three \" ' four five' ' ignored element ", NULL, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_quoted)); + + strv_free(l); + + /* missing last quote, but the last element is _not_ ignored with SPLIT_RELAX. */ + l = strv_split_full(" 'one' \" two\t three \" ' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_quoted)); + + strv_free(l); + + /* missing separator between */ + l = strv_split_full(" 'one' \" two\t three \"' four five'", NULL, SPLIT_QUOTES | SPLIT_RELAX); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_quoted)); + + strv_free(l); + + l = strv_split_full(" 'one' \" two\t three \"' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX); + assert_se(l); + assert_se(strv_equal(l, (char**) input_table_quoted)); +} + +static void test_strv_split_empty(void) { + _cleanup_strv_free_ char **l = NULL; + + l = strv_split("", WHITESPACE); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split("", NULL); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full("", NULL, 0); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full("", NULL, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full("", WHITESPACE, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full("", WHITESPACE, SPLIT_QUOTES | SPLIT_RELAX); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split(" ", WHITESPACE); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split(" ", NULL); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full(" ", NULL, 0); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full(" ", WHITESPACE, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full(" ", NULL, SPLIT_QUOTES); + assert_se(l); + assert_se(strv_isempty(l)); + + strv_free(l); + l = strv_split_full(" ", NULL, SPLIT_QUOTES | SPLIT_RELAX); + assert_se(l); + assert_se(strv_isempty(l)); } static void test_strv_split_extract(void) { @@ -233,18 +395,18 @@ static void test_strv_split_nulstr(void) { static void test_strv_parse_nulstr(void) { _cleanup_strv_free_ char **l = NULL; - const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx"; + const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx"; l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1); assert_se(l); puts("Parse nulstr:"); strv_print(l); - assert_se(streq(l[0], "fuck")); - assert_se(streq(l[1], "fuck2")); - assert_se(streq(l[2], "fuck3")); + assert_se(streq(l[0], "hoge")); + assert_se(streq(l[1], "hoge2")); + assert_se(streq(l[2], "hoge3")); assert_se(streq(l[3], "")); - assert_se(streq(l[4], "fuck5")); + assert_se(streq(l[4], "hoge5")); assert_se(streq(l[5], "")); assert_se(streq(l[6], "xxx")); } @@ -293,8 +455,8 @@ static void test_strv_sort(void) { static void test_strv_extend_strv_concat(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; - a = strv_new("without", "suffix", NULL); - b = strv_new("with", "suffix", NULL); + a = strv_new("without", "suffix"); + b = strv_new("with", "suffix"); assert_se(a); assert_se(b); @@ -309,8 +471,8 @@ static void test_strv_extend_strv_concat(void) { static void test_strv_extend_strv(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL; - a = strv_new("abc", "def", "ghi", NULL); - b = strv_new("jkl", "mno", "abc", "pqr", NULL); + a = strv_new("abc", "def", "ghi"); + b = strv_new("jkl", "mno", "abc", "pqr"); assert_se(a); assert_se(b); @@ -335,7 +497,7 @@ static void test_strv_extend_strv(void) { static void test_strv_extend(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; - a = strv_new("test", "test1", NULL); + a = strv_new("test", "test1"); assert_se(a); assert_se(strv_extend(&a, "test2") >= 0); assert_se(strv_extend(&b, "test3") >= 0); @@ -349,7 +511,7 @@ static void test_strv_extend(void) { static void test_strv_extendf(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; - a = strv_new("test", "test1", NULL); + a = strv_new("test", "test1"); assert_se(a); assert_se(strv_extendf(&a, "test2 %s %d %s", "foo", 128, "bar") >= 0); assert_se(strv_extendf(&b, "test3 %s %s %d", "bar", "foo", 128) >= 0); @@ -365,7 +527,7 @@ static void test_strv_foreach(void) { unsigned i = 0; char **check; - a = strv_new("one", "two", "three", NULL); + a = strv_new("one", "two", "three"); assert_se(a); @@ -379,7 +541,7 @@ static void test_strv_foreach_backwards(void) { unsigned i = 2; char **check; - a = strv_new("one", "two", "three", NULL); + a = strv_new("one", "two", "three"); assert_se(a); @@ -399,8 +561,7 @@ static void test_strv_foreach_pair(void) { a = strv_new("pair_one", "pair_one", "pair_two", "pair_two", - "pair_three", "pair_three", - NULL); + "pair_three", "pair_three"); STRV_FOREACH_PAIR(x, y, a) { assert_se(streq(*x, *y)); @@ -460,7 +621,7 @@ static void test_strv_insert(void) { static void test_strv_push_prepend(void) { _cleanup_strv_free_ char **a = NULL; - a = strv_new("foo", "bar", "three", NULL); + a = strv_new("foo", "bar", "three"); assert_se(strv_push_prepend(&a, strdup("first")) >= 0); assert_se(streq(a[0], "first")); @@ -500,11 +661,11 @@ static void test_strv_equal(void) { _cleanup_strv_free_ char **b = NULL; _cleanup_strv_free_ char **c = NULL; - a = strv_new("one", "two", "three", NULL); + a = strv_new("one", "two", "three"); assert_se(a); - b = strv_new("one", "two", "three", NULL); + b = strv_new("one", "two", "three"); assert_se(a); - c = strv_new("one", "two", "three", "four", NULL); + c = strv_new("one", "two", "three", "four"); assert_se(a); assert_se(strv_equal(a, a)); @@ -519,19 +680,19 @@ static void test_strv_equal(void) { static void test_strv_is_uniq(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; - a = strv_new(NULL, NULL); + a = strv_new(NULL); assert_se(a); assert_se(strv_is_uniq(a)); - b = strv_new("foo", NULL); + b = strv_new("foo"); assert_se(b); assert_se(strv_is_uniq(b)); - c = strv_new("foo", "bar", NULL); + c = strv_new("foo", "bar"); assert_se(c); assert_se(strv_is_uniq(c)); - d = strv_new("foo", "bar", "waldo", "bar", "piep", NULL); + d = strv_new("foo", "bar", "waldo", "bar", "piep"); assert_se(d); assert_se(!strv_is_uniq(d)); } @@ -539,26 +700,26 @@ static void test_strv_is_uniq(void) { static void test_strv_reverse(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; - a = strv_new(NULL, NULL); + a = strv_new(NULL); assert_se(a); strv_reverse(a); assert_se(strv_isempty(a)); - b = strv_new("foo", NULL); + b = strv_new("foo"); assert_se(b); strv_reverse(b); assert_se(streq_ptr(b[0], "foo")); assert_se(streq_ptr(b[1], NULL)); - c = strv_new("foo", "bar", NULL); + c = strv_new("foo", "bar"); assert_se(c); strv_reverse(c); assert_se(streq_ptr(c[0], "bar")); assert_se(streq_ptr(c[1], "foo")); assert_se(streq_ptr(c[2], NULL)); - d = strv_new("foo", "bar", "waldo", NULL); + d = strv_new("foo", "bar", "waldo"); assert_se(d); strv_reverse(d); assert_se(streq_ptr(d[0], "waldo")); @@ -570,7 +731,7 @@ static void test_strv_reverse(void) { static void test_strv_shell_escape(void) { _cleanup_strv_free_ char **v = NULL; - v = strv_new("foo:bar", "bar,baz", "wal\\do", NULL); + v = strv_new("foo:bar", "bar,baz", "wal\\do"); assert_se(v); assert_se(strv_shell_escape(v, ",:")); assert_se(streq_ptr(v[0], "foo\\:bar")); @@ -604,7 +765,7 @@ static void test_strv_skip(void) { static void test_strv_extend_n(void) { _cleanup_strv_free_ char **v = NULL; - v = strv_new("foo", "bar", NULL); + v = strv_new("foo", "bar"); assert_se(v); assert_se(strv_extend_n(&v, "waldo", 3) >= 0); @@ -660,8 +821,8 @@ static void test_strv_free_free(void) { char ***t; assert_se(t = new(char**, 3)); - assert_se(t[0] = strv_new("a", "b", NULL)); - assert_se(t[1] = strv_new("c", "d", "e", NULL)); + assert_se(t[0] = strv_new("a", "b")); + assert_se(t[1] = strv_new("c", "d", "e")); t[2] = NULL; t = strv_free_free(t); @@ -691,7 +852,7 @@ static void test_strv_fnmatch(void) { assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); - v = strv_new("*\\*", NULL); + v = strv_new("*\\*"); assert_se(!strv_fnmatch(v, "\\", 0)); assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE)); } @@ -700,6 +861,7 @@ int main(int argc, char *argv[]) { test_specifier_printf(); test_str_in_set(); test_strptr_in_set(); + test_startswith_set(); test_strv_foreach(); test_strv_foreach_backwards(); test_strv_foreach_pair(); @@ -707,6 +869,7 @@ int main(int argc, char *argv[]) { test_strv_find_prefix(); test_strv_find_startswith(); test_strv_join(); + test_strv_join_prefix(); test_strv_unquote(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz")); test_strv_unquote("", STRV_MAKE_EMPTY); @@ -733,6 +896,7 @@ int main(int argc, char *argv[]) { test_invalid_unquote("'x'y'g"); test_strv_split(); + test_strv_split_empty(); test_strv_split_extract(); test_strv_split_newlines(); test_strv_split_nulstr(); diff --git a/src/test/test-systemd-tmpfiles.py b/src/test/test-systemd-tmpfiles.py index 13a44f3c4a..83a66e8772 100755 --- a/src/test/test-systemd-tmpfiles.py +++ b/src/test/test-systemd-tmpfiles.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1+ # -# 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 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. import os import sys @@ -12,6 +12,7 @@ import socket import subprocess import tempfile import pwd +import grp try: from systemd import id128 @@ -95,9 +96,13 @@ def test_valid_specifiers(*, user): test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user) test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user) test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user) + test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user) - user = pwd.getpwuid(os.getuid()) - test_content('f {} - - - - %u', '{}'.format(user.pw_name), user=user) + puser = pwd.getpwuid(os.getuid()) + test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user) + + pgroup = grp.getgrgid(os.getgid()) + test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user) # Note that %h is the only specifier in which we look the environment, # because we check $HOME. Should we even be doing that? diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 4c3b264989..bce7e3390a 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -6,6 +6,7 @@ #include "cgroup.h" #include "compress.h" #include "condition.h" +#include "device-internal.h" #include "device.h" #include "execute.h" #include "import-util.h" @@ -25,6 +26,7 @@ #include "rlimit-util.h" #include "scope.h" #include "service.h" +#include "show-status.h" #include "slice.h" #include "socket-util.h" #include "socket.h" @@ -51,7 +53,9 @@ int main(int argc, char **argv) { test_table(collect_mode, COLLECT_MODE); test_table(condition_result, CONDITION_RESULT); test_table(condition_type, CONDITION_TYPE); + test_table(device_action, DEVICE_ACTION); test_table(device_state, DEVICE_STATE); + test_table(dns_over_tls_mode, DNS_OVER_TLS_MODE); test_table(dnssec_mode, DNSSEC_MODE); test_table(emergency_action, EMERGENCY_ACTION); test_table(exec_directory_type, EXEC_DIRECTORY_TYPE); @@ -79,6 +83,7 @@ int main(int argc, char **argv) { test_table(name_policy, NAMEPOLICY); test_table(namespace_type, NAMESPACE_TYPE); test_table(notify_access, NOTIFY_ACCESS); + test_table(notify_state, NOTIFY_STATE); test_table(output_mode, OUTPUT_MODE); test_table(partition_designator, PARTITION_DESIGNATOR); test_table(path_result, PATH_RESULT); @@ -95,6 +100,7 @@ int main(int argc, char **argv) { test_table(service_result, SERVICE_RESULT); test_table(service_state, SERVICE_STATE); test_table(service_type, SERVICE_TYPE); + test_table(show_status, SHOW_STATUS); test_table(slice_state, SLICE_STATE); test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY); test_table(socket_exec_command, SOCKET_EXEC_COMMAND); diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index 9f27c74139..958d369430 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -5,11 +5,11 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" -#include "log.h" #include "macro.h" #include "strv.h" #include "terminal-util.h" +#include "tests.h" +#include "tmpfile-util.h" #include "util.h" static void test_default_term_for_tty(void) { @@ -32,15 +32,11 @@ static void test_read_one_char(void) { char r; bool need_nl; char name[] = "/tmp/test-read_one_char.XXXXXX"; - int fd; - fd = mkostemp_safe(name); - assert_se(fd >= 0); - file = fdopen(fd, "r+"); - assert_se(file); + assert(fmkostemp_safe(name, "r+", &file) == 0); + assert_se(fputs("c\n", file) >= 0); rewind(file); - assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0); assert_se(!need_nl); assert_se(r == 'c'); @@ -59,36 +55,11 @@ static void test_read_one_char(void) { unlink(name); } -static void test_terminal_urlify(void) { - _cleanup_free_ char *formatted = NULL; - - assert_se(terminal_urlify("https://www.freedesktop.org/wiki/Software/systemd/", "systemd homepage", &formatted) >= 0); - printf("Hey, considere visiting the %s right now! It is very good!\n", formatted); - - formatted = mfree(formatted); - - assert_se(terminal_urlify_path("/etc/fstab", "this link to your /etc/fstab", &formatted) >= 0); - printf("Or click on %s to have a look at it!\n", formatted); -} - -static void test_cat_files(void) { - assert_se(cat_files("/no/such/file", NULL, 0) == -ENOENT); - assert_se(cat_files("/no/such/file", NULL, CAT_FLAGS_MAIN_FILE_OPTIONAL) == 0); - - if (access("/etc/fstab", R_OK) >= 0) - assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0); -} - int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); test_default_term_for_tty(); test_read_one_char(); - test_terminal_urlify(); - test_cat_files(); - - print_separator(); return 0; } diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 87de8d172c..2ec2ade3f1 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "random-util.h" +#include "serialize.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -36,14 +37,37 @@ static void test_parse_sec(void) { assert_se(u == USEC_INFINITY); assert_se(parse_sec(" infinity ", &u) >= 0); assert_se(u == USEC_INFINITY); + assert_se(parse_sec("+3.1s", &u) >= 0); + assert_se(u == 3100 * USEC_PER_MSEC); + assert_se(parse_sec("3.1s.2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 .2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * USEC_PER_MSEC); assert_se(parse_sec(" xyz ", &u) < 0); assert_se(parse_sec("", &u) < 0); assert_se(parse_sec(" . ", &u) < 0); assert_se(parse_sec(" 5. ", &u) < 0); assert_se(parse_sec(".s ", &u) < 0); + assert_se(parse_sec("-5s ", &u) < 0); + assert_se(parse_sec("-0.3s ", &u) < 0); + assert_se(parse_sec("-0.0s ", &u) < 0); + assert_se(parse_sec("-0.-0s ", &u) < 0); + assert_se(parse_sec("0.-0s ", &u) < 0); + assert_se(parse_sec("3.-0s ", &u) < 0); assert_se(parse_sec(" infinity .7", &u) < 0); assert_se(parse_sec(".3 infinity", &u) < 0); + assert_se(parse_sec("3.+1s", &u) < 0); + assert_se(parse_sec("3. 1s", &u) < 0); + assert_se(parse_sec("3.s", &u) < 0); + assert_se(parse_sec("12.34.56", &u) < 0); + assert_se(parse_sec("12..34", &u) < 0); + assert_se(parse_sec("..1234", &u) < 0); + assert_se(parse_sec("1234..", &u) < 0); } static void test_parse_sec_fix_0(void) { @@ -54,7 +78,7 @@ static void test_parse_sec_fix_0(void) { assert_se(parse_sec_fix_0("5s", &u) >= 0); assert_se(u == 5 * USEC_PER_SEC); assert_se(parse_sec_fix_0("0s", &u) >= 0); - assert_se(u == 0 * USEC_PER_SEC); + assert_se(u == USEC_INFINITY); assert_se(parse_sec_fix_0("0", &u) >= 0); assert_se(u == USEC_INFINITY); assert_se(parse_sec_fix_0(" 0", &u) >= 0); @@ -83,6 +107,9 @@ static void test_parse_time(void) { assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE); + assert_se(parse_time("1.1111111111111y", &u, 1) >= 0); } static void test_parse_nsec(void) { @@ -112,6 +139,16 @@ static void test_parse_nsec(void) { assert_se(u == NSEC_INFINITY); assert_se(parse_nsec(" infinity ", &u) >= 0); assert_se(u == NSEC_INFINITY); + assert_se(parse_nsec("+3.1s", &u) >= 0); + assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1s.2", &u) >= 0); + assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 .2s", &u) >= 0); + assert_se(u == 200 * NSEC_PER_MSEC + 3); + assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * NSEC_PER_MSEC); assert_se(parse_nsec(" xyz ", &u) < 0); assert_se(parse_nsec("", &u) < 0); @@ -120,6 +157,23 @@ static void test_parse_nsec(void) { assert_se(parse_nsec(".s ", &u) < 0); assert_se(parse_nsec(" infinity .7", &u) < 0); assert_se(parse_nsec(".3 infinity", &u) < 0); + assert_se(parse_nsec("-5s ", &u) < 0); + assert_se(parse_nsec("-0.3s ", &u) < 0); + assert_se(parse_nsec("-0.0s ", &u) < 0); + assert_se(parse_nsec("-0.-0s ", &u) < 0); + assert_se(parse_nsec("0.-0s ", &u) < 0); + assert_se(parse_nsec("3.-0s ", &u) < 0); + assert_se(parse_nsec(" infinity .7", &u) < 0); + assert_se(parse_nsec(".3 infinity", &u) < 0); + assert_se(parse_nsec("3.+1s", &u) < 0); + assert_se(parse_nsec("3. 1s", &u) < 0); + assert_se(parse_nsec("3.s", &u) < 0); + assert_se(parse_nsec("12.34.56", &u) < 0); + assert_se(parse_nsec("12..34", &u) < 0); + assert_se(parse_nsec("..1234", &u) < 0); + assert_se(parse_nsec("1234..", &u) < 0); + assert_se(parse_nsec("1111111111111y", &u) == -ERANGE); + assert_se(parse_nsec("1.111111111111y", &u) >= 0); } static void test_format_timespan_one(usec_t x, usec_t accuracy) { @@ -311,40 +365,40 @@ static void test_format_timestamp_utc(void) { test_format_timestamp_utc_one(USEC_INFINITY, NULL); } -static void test_dual_timestamp_deserialize(void) { +static void test_deserialize_dual_timestamp(void) { int r; dual_timestamp t; log_info("/* %s */", __func__); - r = dual_timestamp_deserialize("1234 5678", &t); + r = deserialize_dual_timestamp("1234 5678", &t); assert_se(r == 0); assert_se(t.realtime == 1234); assert_se(t.monotonic == 5678); - r = dual_timestamp_deserialize("1234x 5678", &t); + r = deserialize_dual_timestamp("1234x 5678", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("1234 5678y", &t); + r = deserialize_dual_timestamp("1234 5678y", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("-1234 5678", &t); + r = deserialize_dual_timestamp("-1234 5678", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("1234 -5678", &t); + r = deserialize_dual_timestamp("1234 -5678", &t); assert_se(r == -EINVAL); /* Check that output wasn't modified. */ assert_se(t.realtime == 1234); assert_se(t.monotonic == 5678); - r = dual_timestamp_deserialize("+123 567", &t); + r = deserialize_dual_timestamp("+123 567", &t); assert_se(r == 0); assert_se(t.realtime == 123); assert_se(t.monotonic == 567); /* Check that we get "infinity" on overflow. */ - r = dual_timestamp_deserialize("18446744073709551617 0", &t); + r = deserialize_dual_timestamp("18446744073709551617 0", &t); assert_se(r == 0); assert_se(t.realtime == USEC_INFINITY); assert_se(t.monotonic == 0); @@ -432,7 +486,7 @@ int main(int argc, char *argv[]) { test_usec_sub_unsigned(); test_format_timestamp(); test_format_timestamp_utc(); - test_dual_timestamp_deserialize(); + test_deserialize_dual_timestamp(); test_usec_shift_clock(); test_in_utc_timezone(); diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 3817790233..b526871655 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -13,6 +13,8 @@ #include "log.h" #include "process-util.h" #include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" #include "util.h" int main(int argc, char** argv) { @@ -21,8 +23,7 @@ int main(int argc, char** argv) { const char *p = argv[1] ?: "/tmp"; char *pattern; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); pattern = strjoina(p, "/systemd-test-XXXXXX"); diff --git a/src/test/test-udev.c b/src/test/test-udev.c index bed51c1270..7a4622b875 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -11,13 +11,16 @@ #include <sys/signalfd.h> #include <unistd.h> +#include "device-private.h" #include "fs-util.h" #include "log.h" +#include "main-func.h" #include "missing.h" +#include "mkdir.h" #include "selinux-util.h" #include "signal-util.h" #include "string-util.h" -#include "udev-util.h" +#include "tests.h" #include "udev.h" static int fake_filesystems(void) { @@ -27,106 +30,102 @@ static int fake_filesystems(void) { const char *error; bool ignore_mount_error; } fakefss[] = { - { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false }, - { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false }, - { "test/run", "/run", "failed to mount test /run", false }, - { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true }, - { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, + { "test/tmpfs/sys", "/sys", "Failed to mount test /sys", false }, + { "test/tmpfs/dev", "/dev", "Failed to mount test /dev", false }, + { "test/run", "/run", "Failed to mount test /run", false }, + { "test/run", "/etc/udev/rules.d", "Failed to mount empty /etc/udev/rules.d", true }, + { "test/run", UDEVLIBEXECDIR "/rules.d", "Failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, }; - unsigned int i; + unsigned i; if (unshare(CLONE_NEWNS) < 0) - return log_error_errno(errno, "failed to call unshare(): %m"); + return log_error_errno(errno, "Failed to call unshare(): %m"); - if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) - return log_error_errno(errno, "failed to mount / as private: %m"); + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) + return log_error_errno(errno, "Failed to mount / as private: %m"); - for (i = 0; i < ELEMENTSOF(fakefss); i++) { + for (i = 0; i < ELEMENTSOF(fakefss); i++) if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error); if (!fakefss[i].ignore_mount_error) return -errno; } - } return 0; } -int main(int argc, char *argv[]) { - _cleanup_(udev_unrefp) struct udev *udev = NULL; - _cleanup_(udev_event_unrefp) struct udev_event *event = NULL; - _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; - _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL; - char syspath[UTIL_PATH_SIZE]; - const char *devpath; - const char *action; - int err; +static int run(int argc, char *argv[]) { + _cleanup_(udev_rules_freep) UdevRules *rules = NULL; + _cleanup_(udev_event_freep) UdevEvent *event = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *devpath, *devname, *action; + int r; + + test_setup_logging(LOG_INFO); - log_parse_environment(); - log_open(); + if (!IN_SET(argc, 2, 3)) { + log_error("This program needs one or two arguments, %d given", argc - 1); + return -EINVAL; + } - err = fake_filesystems(); - if (err < 0) - return EXIT_FAILURE; + r = fake_filesystems(); + if (r < 0) + return r; - udev = udev_new(); - if (udev == NULL) - return EXIT_FAILURE; + if (argc == 2) { + if (!streq(argv[1], "check")) { + log_error("Unknown argument: %s", argv[1]); + return -EINVAL; + } + + return 0; + } log_debug("version %s", PACKAGE_VERSION); mac_selinux_init(); action = argv[1]; - if (action == NULL) { - log_error("action missing"); - goto out; - } - devpath = argv[2]; - if (devpath == NULL) { - log_error("devpath missing"); - goto out; - } - rules = udev_rules_new(udev, 1); + assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0); - strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL); - dev = udev_device_new_from_synthetic_event(udev, syspath, action); - if (dev == NULL) { - log_debug("unknown device '%s'", devpath); - goto out; - } + const char *syspath = strjoina("/sys", devpath); + r = device_new_from_synthetic_event(&dev, syspath, action); + if (r < 0) + return log_debug_errno(r, "Failed to open device '%s'", devpath); - event = udev_event_new(dev); + assert_se(event = udev_event_new(dev, 0, NULL)); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); /* do what devtmpfs usually provides us */ - if (udev_device_get_devnode(dev) != NULL) { + if (sd_device_get_devname(dev, &devname) >= 0) { + const char *subsystem; mode_t mode = 0600; - if (streq(udev_device_get_subsystem(dev), "block")) + if (sd_device_get_subsystem(dev, &subsystem) >= 0 && streq(subsystem, "block")) mode |= S_IFBLK; else mode |= S_IFCHR; if (!streq(action, "remove")) { - mkdir_parents_label(udev_device_get_devnode(dev), 0755); - mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev)); + dev_t devnum = makedev(0, 0); + + (void) mkdir_parents_label(devname, 0755); + (void) sd_device_get_devnum(dev, &devnum); + if (mknod(devname, mode, devnum) < 0) + return log_error_errno(errno, "mknod() failed for '%s': %m", devname); } else { - unlink(udev_device_get_devnode(dev)); - rmdir_parents(udev_device_get_devnode(dev), "/"); + if (unlink(devname) < 0) + return log_error_errno(errno, "unlink('%s') failed: %m", devname); + (void) rmdir_parents(devname, "/"); } } - udev_event_execute_rules(event, - 3 * USEC_PER_SEC, USEC_PER_SEC, - NULL, - rules); - udev_event_execute_run(event, - 3 * USEC_PER_SEC, USEC_PER_SEC); -out: - mac_selinux_finish(); + udev_event_execute_rules(event, 3 * USEC_PER_SEC, NULL, rules); + udev_event_execute_run(event, 3 * USEC_PER_SEC); - return err ? EXIT_FAILURE : EXIT_SUCCESS; + return 0; } + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/test/test-umount.c b/src/test/test-umount.c index 770d1a73c8..6ab5758ede 100644 --- a/src/test/test-umount.c +++ b/src/test/test-umount.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include "alloc-util.h" #include "log.h" +#include "path-util.h" #include "string-util.h" #include "tests.h" #include "umount.h" @@ -8,10 +10,14 @@ static void test_mount_points_list(const char *fname) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); + _cleanup_free_ char *testdata_fname = NULL; MountPoint *m; log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/self/mountinfo"); + if (fname) + fname = testdata_fname = path_join(get_testdata_dir(), fname); + LIST_HEAD_INIT(mp_list_head); assert_se(mount_points_list_get(fname, &mp_list_head) >= 0); @@ -26,10 +32,14 @@ static void test_mount_points_list(const char *fname) { static void test_swap_list(const char *fname) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); + _cleanup_free_ char *testdata_fname = NULL; MountPoint *m; log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/swaps"); + if (fname) + fname = testdata_fname = path_join(get_testdata_dir(), fname); + LIST_HEAD_INIT(mp_list_head); assert_se(swap_list_get(fname, &mp_list_head) >= 0); @@ -43,15 +53,13 @@ static void test_swap_list(const char *fname) { } int main(int argc, char **argv) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_mount_points_list(NULL); - test_mount_points_list(get_testdata_dir("/test-umount/empty.mountinfo")); - test_mount_points_list(get_testdata_dir("/test-umount/garbled.mountinfo")); - test_mount_points_list(get_testdata_dir("/test-umount/rhbug-1554943.mountinfo")); + test_mount_points_list("/test-umount/empty.mountinfo"); + test_mount_points_list("/test-umount/garbled.mountinfo"); + test_mount_points_list("/test-umount/rhbug-1554943.mountinfo"); test_swap_list(NULL); - test_swap_list(get_testdata_dir("/test-umount/example.swaps")); + test_swap_list("/test-umount/example.swaps"); } diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 09b0179fa1..f5578f9fc2 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -7,12 +7,12 @@ #include <sys/capability.h> #include <unistd.h> -#include "alloc-util.h" #include "all-units.h" +#include "alloc-util.h" #include "capability-util.h" #include "conf-parser.h" +#include "env-file.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "hashmap.h" #include "hostname-util.h" @@ -26,6 +26,7 @@ #include "strv.h" #include "test-helper.h" #include "tests.h" +#include "tmpfile-util.h" #include "user-util.h" #include "util.h" @@ -39,11 +40,8 @@ static int test_unit_file_get_set(void) { assert_se(h); r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); - - if (IN_SET(r, -EPERM, -EACCES)) { - log_notice_errno(r, "Skipping test: unit_file_get_list: %m"); - return EXIT_TEST_SKIP; - } + if (IN_SET(r, -EPERM, -EACCES)) + return log_tests_skipped_errno(r, "unit_file_get_list"); log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r, "unit_file_get_list: %m"); @@ -532,9 +530,9 @@ static void test_load_env_file_1(void) { fd = mkostemp_safe(name); assert_se(fd >= 0); - assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1)); + assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=a")); assert_se(streq(data[1], "b=bc")); @@ -554,9 +552,9 @@ static void test_load_env_file_2(void) { fd = mkostemp_safe(name); assert_se(fd >= 0); - assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2)); + assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=a")); assert_se(data[1] == NULL); @@ -571,9 +569,9 @@ static void test_load_env_file_3(void) { fd = mkostemp_safe(name); assert_se(fd >= 0); - assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3)); + assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(data == NULL); } @@ -586,9 +584,9 @@ static void test_load_env_file_4(void) { fd = mkostemp_safe(name); assert_se(fd >= 0); - assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4)); + assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); assert_se(streq(data[1], "MODULE_0=coretemp")); @@ -605,9 +603,9 @@ static void test_load_env_file_5(void) { fd = mkostemp_safe(name); assert_se(fd >= 0); - assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5)); + assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5)); - r = load_env_file(NULL, name, NULL, &data); + r = load_env_file(NULL, name, &data); assert_se(r == 0); assert_se(streq(data[0], "a=")); assert_se(streq(data[1], "b=")); @@ -624,11 +622,13 @@ static void test_install_printf(void) { UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; - _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); + assert_se(group = gid_to_name(getgid())); + assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0); assert_se(user = uid_to_name(getuid())); assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); @@ -655,6 +655,8 @@ static void test_install_printf(void) { expect(i, "%p", "name"); expect(i, "%i", ""); expect(i, "%j", "name"); + expect(i, "%g", group); + expect(i, "%G", gid); expect(i, "%u", user); expect(i, "%U", uid); @@ -662,12 +664,16 @@ static void test_install_printf(void) { expect(i, "%b", bid); expect(i, "%H", host); + expect(i2, "%g", group); + expect(i2, "%G", gid); expect(i2, "%u", user); expect(i2, "%U", uid); expect(i3, "%n", "name@inst.service"); expect(i3, "%N", "name@inst"); expect(i3, "%p", "name"); + expect(i3, "%g", group); + expect(i3, "%G", gid); expect(i3, "%u", user); expect(i3, "%U", uid); @@ -675,6 +681,8 @@ static void test_install_printf(void) { expect(i3, "%b", bid); expect(i3, "%H", host); + expect(i4, "%g", group); + expect(i4, "%G", gid); expect(i4, "%u", user); expect(i4, "%U", uid); } @@ -896,14 +904,11 @@ int main(int argc, char *argv[]) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int r; - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); assert_se(runtime_dir = setup_fake_runtime_dir()); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 2b00ef8cb7..2afae22510 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -191,7 +191,7 @@ static void test_unit_name_mangle(void) { } static int test_unit_printf(void) { - _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; _cleanup_(manager_freep) Manager *m = NULL; Unit *u; int r; @@ -200,15 +200,15 @@ static int test_unit_printf(void) { assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); assert_se(user = uid_to_name(getuid())); + assert_se(group = gid_to_name(getgid())); assert_se(asprintf(&uid, UID_FMT, getuid())); + assert_se(asprintf(&gid, UID_FMT, getgid())); assert_se(get_home_dir(&home) >= 0); assert_se(get_shell(&shell) >= 0); r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m); - if (MANAGER_SKIP_TEST(r)) { - log_notice_errno(r, "Skipping test: manager_new: %m"); - return EXIT_TEST_SKIP; - } + if (MANAGER_SKIP_TEST(r)) + return log_tests_skipped_errno(r, "manager_new"); assert_se(r == 0); #define expect(unit, pattern, expected) \ @@ -243,6 +243,8 @@ static int test_unit_printf(void) { expect(u, "%I", ""); expect(u, "%j", "blah"); expect(u, "%J", "blah"); + expect(u, "%g", group); + expect(u, "%G", gid); expect(u, "%u", user); expect(u, "%U", uid); expect(u, "%h", home); @@ -265,6 +267,8 @@ static int test_unit_printf(void) { expect(u, "%I", "foo/foo"); expect(u, "%j", "blah"); expect(u, "%J", "blah"); + expect(u, "%g", group); + expect(u, "%G", gid); expect(u, "%u", user); expect(u, "%U", uid); expect(u, "%h", home); @@ -528,7 +532,6 @@ static void test_unit_name_from_dbus_path(void) { test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/accounts_2ddaemon_2eservice", 0, "accounts-daemon.service"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/auditd_2eservice", 0, "auditd.service"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/basic_2etarget", 0, "basic.target"); - test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/bluetooth_2etarget", 0, "bluetooth.target"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/boot_2eautomount", 0, "boot.automount"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/boot_2emount", 0, "boot.mount"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/btrfs_2emount", 0, "btrfs.mount"); @@ -811,14 +814,11 @@ int main(int argc, char* argv[]) { _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int r, rc = 0; - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping test: cgroupfs not available"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); assert_se(runtime_dir = setup_fake_runtime_dir()); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index c1428fab02..801824ad67 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -159,7 +159,7 @@ static void test_get_user_creds_one(const char *id, const char *name, uid_t uid, log_info("/* %s(\"%s\", \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\") */", __func__, id, name, uid, gid, home, shell); - r = get_user_creds(&id, &ruid, &rgid, &rhome, &rshell); + r = get_user_creds(&id, &ruid, &rgid, &rhome, &rshell, 0); log_info_errno(r, "got \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\": %m", id, ruid, rgid, strnull(rhome), strnull(rshell)); if (!synthesize_nobody() && streq(name, NOBODY_USER_NAME)) { @@ -180,7 +180,7 @@ static void test_get_group_creds_one(const char *id, const char *name, gid_t gid log_info("/* %s(\"%s\", \"%s\", "GID_FMT") */", __func__, id, name, gid); - r = get_group_creds(&id, &rgid); + r = get_group_creds(&id, &rgid, 0); log_info_errno(r, "got \"%s\", "GID_FMT": %m", id, rgid); if (!synthesize_nobody() && streq(name, NOBODY_GROUP_NAME)) { log_info("(skipping detailed tests because nobody is not synthesized)"); @@ -191,7 +191,7 @@ static void test_get_group_creds_one(const char *id, const char *name, gid_t gid assert_se(rgid == gid); } -int main(int argc, char*argv[]) { +int main(int argc, char *argv[]) { test_uid_to_name_one(0, "root"); test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME); test_uid_to_name_one(0xFFFF, "65535"); diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index fe3db314a0..9849530ac8 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -1,10 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Dave Reisner -***/ #include "alloc-util.h" #include "string-util.h" +#include "strv.h" #include "utf8.h" #include "util.h" @@ -90,15 +88,25 @@ static void test_utf8_escaping_printable(void) { } static void test_utf16_to_utf8(void) { - char *a = NULL; - const uint16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) }; - const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7, 0 }; + const char16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) }; + static const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7 }; + _cleanup_free_ char16_t *b = NULL; + _cleanup_free_ char *a = NULL; - a = utf16_to_utf8(utf16, 14); + /* Convert UTF-16 to UTF-8, filtering embedded bad chars */ + a = utf16_to_utf8(utf16, sizeof(utf16)); assert_se(a); - assert_se(streq(a, utf8)); + assert_se(memcmp(a, utf8, sizeof(utf8)) == 0); + + /* Convert UTF-8 to UTF-16, and back */ + b = utf8_to_utf16(utf8, sizeof(utf8)); + assert_se(b); free(a); + a = utf16_to_utf8(b, char16_strlen(b) * 2); + assert_se(a); + assert_se(strlen(a) == sizeof(utf8)); + assert_se(memcmp(a, utf8, sizeof(utf8)) == 0); } static void test_utf8_n_codepoints(void) { @@ -119,6 +127,28 @@ static void test_utf8_console_width(void) { assert_se(utf8_console_width("\xF1") == (size_t) -1); } +static void test_utf8_to_utf16(void) { + const char *p; + + FOREACH_STRING(p, + "abc", + "zażółcić gęślą jaźń", + "串", + "", + "…👊🔪💐…") { + + _cleanup_free_ char16_t *a = NULL; + _cleanup_free_ char *b = NULL; + + a = utf8_to_utf16(p, strlen(p)); + assert_se(a); + + b = utf16_to_utf8(a, char16_strlen(a) * 2); + assert_se(b); + assert_se(streq(p, b)); + } +} + int main(int argc, char *argv[]) { test_utf8_is_valid(); test_utf8_is_printable(); @@ -130,6 +160,7 @@ int main(int argc, char *argv[]) { test_utf16_to_utf8(); test_utf8_n_codepoints(); test_utf8_console_width(); + test_utf8_to_utf16(); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 4d3e5c5b94..3c1b5f9b41 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -8,16 +8,20 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "missing_syscall.h" #include "parse-util.h" #include "process-util.h" #include "raw-clone.h" #include "rm-rf.h" #include "string-util.h" +#include "tests.h" #include "util.h" static void test_align_power2(void) { unsigned long i, p2; + log_info("/* %s */", __func__); + assert_se(ALIGN_POWER2(0) == 0); assert_se(ALIGN_POWER2(1) == 1); assert_se(ALIGN_POWER2(2) == 2); @@ -53,6 +57,14 @@ static void test_max(void) { .a = CONST_MAX(10, 100), }; int d = 0; + unsigned long x = 12345; + unsigned long y = 54321; + const char str[] = "a_string_constant"; + const unsigned long long arr[] = {9999ULL, 10ULL, 0ULL, 3000ULL, 2000ULL, 1000ULL, 100ULL, 9999999ULL}; + void *p = (void *)str; + void *q = (void *)&str[16]; + + log_info("/* %s */", __func__); assert_cc(sizeof(val1.b) == sizeof(int) * 100); @@ -80,6 +92,35 @@ static void test_max(void) { assert_se(LESS_BY(4, 8) == 0); assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); + assert_se(CMP(3, 5) == -1); + assert_se(CMP(5, 3) == 1); + assert_se(CMP(5, 5) == 0); + assert_se(CMP(x, y) == -1); + assert_se(CMP(y, x) == 1); + assert_se(CMP(x, x) == 0); + assert_se(CMP(y, y) == 0); + assert_se(CMP(UINT64_MAX, (uint64_t) 0) == 1); + assert_se(CMP((uint64_t) 0, UINT64_MAX) == -1); + assert_se(CMP(UINT64_MAX, UINT64_MAX) == 0); + assert_se(CMP(INT64_MIN, INT64_MAX) == -1); + assert_se(CMP(INT64_MAX, INT64_MIN) == 1); + assert_se(CMP(INT64_MAX, INT64_MAX) == 0); + assert_se(CMP(INT64_MIN, INT64_MIN) == 0); + assert_se(CMP(INT64_MAX, (int64_t) 0) == 1); + assert_se(CMP((int64_t) 0, INT64_MIN) == 1); + assert_se(CMP(INT64_MIN, (int64_t) 0) == -1); + assert_se(CMP((int64_t) 0, INT64_MAX) == -1); + assert_se(CMP(&str[2], &str[7]) == -1); + assert_se(CMP(&str[2], &str[2]) == 0); + assert_se(CMP(&str[7], (const char *)str) == 1); + assert_se(CMP(str[2], str[7]) == 1); + assert_se(CMP(str[7], *str) == 1); + assert_se(CMP((const unsigned long long *)arr, &arr[3]) == -1); + assert_se(CMP(*arr, arr[3]) == 1); + assert_se(CMP(p, q) == -1); + assert_se(CMP(q, p) == 1); + assert_se(CMP(p, p) == 0); + assert_se(CMP(q, q) == 0); assert_se(CLAMP(-5, 0, 1) == 0); assert_se(CLAMP(5, 0, 1) == 1); assert_se(CLAMP(5, -10, 1) == 1); @@ -100,6 +141,8 @@ static void test_container_of(void) { uint32_t v2; } _packed_ myval = { }; + log_info("/* %s */", __func__); + assert_cc(sizeof(myval) == 17); assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); @@ -115,6 +158,8 @@ static void test_container_of(void) { static void test_div_round_up(void) { int div; + log_info("/* %s */", __func__); + /* basic tests */ assert_se(DIV_ROUND_UP(0, 8) == 0); assert_se(DIV_ROUND_UP(1, 8) == 1); @@ -146,6 +191,8 @@ static void test_div_round_up(void) { } static void test_u64log2(void) { + log_info("/* %s */", __func__); + assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); assert_se(u64log2(9) == 3); @@ -156,6 +203,8 @@ static void test_u64log2(void) { } static void test_protect_errno(void) { + log_info("/* %s */", __func__); + errno = 12; { PROTECT_ERRNO; @@ -165,6 +214,8 @@ static void test_protect_errno(void) { } static void test_in_set(void) { + log_info("/* %s */", __func__); + assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); assert_se(IN_SET(2, 1, 2, 3, 4)); @@ -175,6 +226,8 @@ static void test_in_set(void) { } static void test_log2i(void) { + log_info("/* %s */", __func__); + assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); assert_se(log2i(3) == 1); @@ -185,9 +238,25 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } +static void test_eqzero(void) { + const uint32_t zeros[] = {0, 0, 0}; + const uint32_t ones[] = {1, 1}; + const uint32_t mixed[] = {0, 1, 0, 0, 0}; + const uint8_t longer[] = {[55] = 255}; + + log_info("/* %s */", __func__); + + assert_se(eqzero(zeros)); + assert_se(!eqzero(ones)); + assert_se(!eqzero(mixed)); + assert_se(!eqzero(longer)); +} + static void test_raw_clone(void) { pid_t parent, pid, pid2; + log_info("/* %s */", __func__); + parent = getpid(); log_info("before clone: getpid()→"PID_FMT, parent); assert_se(raw_getpid() == parent); @@ -218,6 +287,8 @@ static void test_physical_memory(void) { uint64_t p; char buf[FORMAT_BYTES_MAX]; + log_info("/* %s */", __func__); + p = physical_memory(); assert_se(p > 0); assert_se(p < UINT64_MAX); @@ -229,6 +300,8 @@ static void test_physical_memory(void) { static void test_physical_memory_scale(void) { uint64_t p; + log_info("/* %s */", __func__); + p = physical_memory(); assert_se(physical_memory_scale(0, 100) == 0); @@ -263,6 +336,8 @@ static void test_physical_memory_scale(void) { static void test_system_tasks_max(void) { uint64_t t; + log_info("/* %s */", __func__); + t = system_tasks_max(); assert_se(t > 0); assert_se(t < UINT64_MAX); @@ -273,6 +348,8 @@ static void test_system_tasks_max(void) { static void test_system_tasks_max_scale(void) { uint64_t t; + log_info("/* %s */", __func__); + t = system_tasks_max(); assert_se(system_tasks_max_scale(0, 100) == 0); @@ -298,8 +375,7 @@ static void test_system_tasks_max_scale(void) { } int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); + test_setup_logging(LOG_INFO); test_align_power2(); test_max(); @@ -309,6 +385,7 @@ int main(int argc, char *argv[]) { test_protect_errno(); test_in_set(); test_log2i(); + test_eqzero(); test_raw_clone(); test_physical_memory(); test_physical_memory_scale(); diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c index cb43b35bc5..2c6ca0a1a2 100644 --- a/src/test/test-watch-pid.c +++ b/src/test/test-watch-pid.c @@ -13,25 +13,18 @@ int main(int argc, char *argv[]) { Unit *a, *b, *c, *u; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); - - if (getuid() != 0) { - log_notice("Not running as root, skipping kernel related tests."); - return EXIT_TEST_SKIP; - } + test_setup_logging(LOG_DEBUG); + if (getuid() != 0) + return log_tests_skipped("not root"); r = enter_cgroup_subroot(); - if (r == -ENOMEDIUM) { - log_notice("cgroupfs not available, skipping tests"); - return EXIT_TEST_SKIP; - } + if (r == -ENOMEDIUM) + return log_tests_skipped("cgroupfs not available"); - assert_se(set_unit_path(get_testdata_dir("")) >= 0); + assert_se(set_unit_path(get_testdata_dir()) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - assert_se(manager_new(UNIT_FILE_USER, true, &m) >= 0); + assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); assert_se(manager_startup(m, NULL, NULL) >= 0); assert_se(a = unit_new(m, sizeof(Service))); diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c index 2aba3b5a26..ab66d5c49d 100644 --- a/src/test/test-watchdog.c +++ b/src/test/test-watchdog.c @@ -3,8 +3,8 @@ #include <string.h> #include <unistd.h> -#include "env-util.h" #include "log.h" +#include "tests.h" #include "watchdog.h" int main(int argc, char *argv[]) { @@ -13,11 +13,9 @@ int main(int argc, char *argv[]) { int r; bool slow; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); + test_setup_logging(LOG_DEBUG); - r = getenv_bool("SYSTEMD_SLOW_TESTS"); - slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT; + slow = slow_tests_enabled(); t = slow ? 10 * USEC_PER_SEC : 1 * USEC_PER_SEC; count = slow ? 5 : 3; diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c index 72720dccb8..3e6df96c5d 100644 --- a/src/test/test-xattr-util.c +++ b/src/test/test-xattr-util.c @@ -8,10 +8,11 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "macro.h" #include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" #include "xattr-util.h" static void test_fgetxattrat_fake(void) { @@ -78,9 +79,7 @@ static void test_getcrtime(void) { } int main(void) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_fgetxattrat_fake(); test_getcrtime(); |