Systemd/src/test/test-engine.c

131 lines
5.8 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1+ */
2010-01-20 18:26:29 +01:00
#include <errno.h>
#include <stdio.h>
2010-01-20 18:26:29 +01:00
#include <string.h>
#include "bus-util.h"
#include "manager.h"
#include "rm-rf.h"
#include "test-helper.h"
#include "tests.h"
2010-01-20 18:26:29 +01:00
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
2018-03-09 21:55:55 +01:00
_cleanup_(manager_freep) Manager *m = NULL;
2018-03-21 19:55:54 +01:00
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL, *unit_with_multiple_dashes = NULL;
2010-01-20 18:26:29 +01:00
Job *j;
int r;
2010-01-20 18:26:29 +01:00
test_setup_logging(LOG_DEBUG);
2018-03-21 19:55:54 +01:00
r = enter_cgroup_subroot();
if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available");
tests: when running a manager object in a test, migrate to private cgroup subroot first (#6576) Without this "meson test" will end up running all tests in the same cgroup root, and they all will try to manage it. Which usually isn't too bad, except when they end up clearing up each other's cgroups. This race is hard to trigger but has caused various CI runs to fail spuriously. With this change we simply move every test that runs a manager object into their own private cgroup. Note that we don't clean up the cgroup at the end, we leave that to the cgroup manager around it. This fixes races that become visible by test runs throwing out errors like this: ``` exec-systemcallfilter-failing.service: Passing 0 fds to service exec-systemcallfilter-failing.service: About to execute: /bin/echo 'This should not be seen' exec-systemcallfilter-failing.service: Forked /bin/echo as 5693 exec-systemcallfilter-failing.service: Changed dead -> start exec-systemcallfilter-failing.service: Failed to attach to cgroup /exec-systemcallfilter-failing.service: No such file or directory Received SIGCHLD from PID 5693 ((echo)). Child 5693 ((echo)) died (code=exited, status=219/CGROUP) exec-systemcallfilter-failing.service: Child 5693 belongs to exec-systemcallfilter-failing.service exec-systemcallfilter-failing.service: Main process exited, code=exited, status=219/CGROUP exec-systemcallfilter-failing.service: Changed start -> failed exec-systemcallfilter-failing.service: Unit entered failed state. exec-systemcallfilter-failing.service: Failed with result 'exit-code'. exec-systemcallfilter-failing.service: cgroup is empty Assertion 'service->main_exec_status.status == status_expected' failed at ../src/src/test/test-execute.c:71, function check(). Aborting. ``` BTW, I tracked this race down by using perf: ``` # perf record -e cgroup:cgroup_mkdir,cgroup_rmdir … # perf script ``` Thanks a lot @iaguis, @alban for helping me how to use perf for this. Fixes #5895.
2017-08-09 15:42:49 +02:00
/* prepare the test */
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))
return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
2010-01-20 18:26:29 +01:00
printf("Load1:\n");
assert_se(manager_load_startable_unit_or_warn(m, "a.service", NULL, &a) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "b.service", NULL, &b) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "c.service", NULL, &c) >= 0);
2010-01-26 21:39:06 +01:00
manager_dump_units(m, stdout, "\t");
2010-01-20 18:26:29 +01:00
printf("Test1: (Trivial)\n");
r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
if (sd_bus_error_is_set(&err))
log_error("error: %s: %s", err.name, err.message);
assert_se(r == 0);
2010-01-20 18:26:29 +01:00
manager_dump_jobs(m, stdout, "\t");
printf("Load2:\n");
2010-01-20 18:26:29 +01:00
manager_clear_jobs(m);
assert_se(manager_load_startable_unit_or_warn(m, "d.service", NULL, &d) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "e.service", NULL, &e) >= 0);
2010-01-26 21:39:06 +01:00
manager_dump_units(m, stdout, "\t");
2010-01-20 18:26:29 +01:00
printf("Test2: (Cyclic Order, Unfixable)\n");
assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
2010-01-20 18:26:29 +01:00
manager_dump_jobs(m, stdout, "\t");
2010-01-21 00:51:37 +01:00
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
2010-01-20 18:26:29 +01:00
manager_dump_jobs(m, stdout, "\t");
2010-01-21 00:51:37 +01:00
printf("Test4: (Identical transaction)\n");
assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
2010-01-21 00:51:37 +01:00
manager_dump_jobs(m, stdout, "\t");
printf("Load3:\n");
assert_se(manager_load_startable_unit_or_warn(m, "g.service", NULL, &g) >= 0);
2010-01-26 21:39:06 +01:00
manager_dump_units(m, stdout, "\t");
2010-01-21 00:51:37 +01:00
printf("Test5: (Colliding transaction, fail)\n");
assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
2010-01-21 00:51:37 +01:00
printf("Test6: (Colliding transaction, replace)\n");
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
2010-01-21 00:51:37 +01:00
manager_dump_jobs(m, stdout, "\t");
printf("Test7: (Unmergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
printf("Test8: (Mergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
printf("Test9: (Unmergeable job type, replace)\n");
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
printf("Load4:\n");
assert_se(manager_load_startable_unit_or_warn(m, "h.service", NULL, &h) >= 0);
2010-01-26 21:39:06 +01:00
manager_dump_units(m, stdout, "\t");
printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, b, true, UNIT_DEPENDENCY_UDEV) == 0);
assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, c, true, UNIT_DEPENDENCY_PROC_SWAP) == 0);
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
unit_remove_dependencies(a, UNIT_DEPENDENCY_UDEV);
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
unit_remove_dependencies(a, UNIT_DEPENDENCY_PROC_SWAP);
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
2018-03-21 19:55:54 +01:00
assert_se(manager_load_unit(m, "unit-with-multiple-dashes.service", NULL, NULL, &unit_with_multiple_dashes) >= 0);
assert_se(strv_equal(unit_with_multiple_dashes->documentation, STRV_MAKE("man:test", "man:override2", "man:override3")));
assert_se(streq_ptr(unit_with_multiple_dashes->description, "override4"));
2010-01-20 18:26:29 +01:00
return 0;
}