]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-path.c
test: skip test-path on Salsa CI
[thirdparty/systemd.git] / src / test / test-path.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
bc999297 2
bc999297 3#include <stdbool.h>
edb3ca0d
FB
4#include <sys/stat.h>
5#include <sys/types.h>
bc999297 6
b5efdb8a 7#include "alloc-util.h"
57b7a260 8#include "all-units.h"
f4f15635
LP
9#include "fd-util.h"
10#include "fs-util.h"
bc999297 11#include "macro.h"
07630cea 12#include "manager.h"
bc999297 13#include "mkdir.h"
55890a40 14#include "path-util.h"
c6878637 15#include "rm-rf.h"
07630cea
LP
16#include "string-util.h"
17#include "strv.h"
d2120590 18#include "tests.h"
07630cea 19#include "unit.h"
bc999297
RC
20
21typedef void (*test_function_t)(Manager *m);
22
23static int setup_test(Manager **m) {
24 char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
25 "directorynotempty", "makedirectory");
a7f7d1bd 26 Manager *tmp = NULL;
bc999297
RC
27 int r;
28
29 assert_se(m);
30
64ad9e08 31 r = enter_cgroup_subroot(NULL);
317bb217
ZJS
32 if (r == -ENOMEDIUM)
33 return log_tests_skipped("cgroupfs not available");
8c759b33 34
4870133b 35 r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
5eecb103 36 if (manager_errno_skip_test(r))
730d989a 37 return log_tests_skipped_errno(r, "manager_new");
bc999297 38 assert_se(r >= 0);
2a7cf953 39 assert_se(manager_startup(tmp, NULL, NULL, NULL) >= 0);
bc999297
RC
40
41 STRV_FOREACH(test_path, tests_path) {
c6878637
LP
42 _cleanup_free_ char *p = NULL;
43
605405c6 44 p = strjoin("/tmp/test-path_", *test_path);
c6878637
LP
45 assert_se(p);
46
47 (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
bc999297
RC
48 }
49
50 *m = tmp;
51
52 return 0;
53}
54
55static void shutdown_test(Manager *m) {
56 assert_se(m);
57
58 manager_free(m);
59}
60
708961c7 61static Service *service_for_path(Manager *m, Path *path, const char *service_name) {
bc999297
RC
62 _cleanup_free_ char *tmp = NULL;
63 Unit *service_unit = NULL;
bc999297
RC
64
65 assert_se(m);
708961c7 66 assert_se(path);
bc999297
RC
67
68 if (!service_name) {
708961c7 69 assert_se(tmp = strreplace(UNIT(path)->id, ".path", ".service"));
bc999297
RC
70 service_unit = manager_get_unit(m, tmp);
71 } else
72 service_unit = manager_get_unit(m, service_name);
73 assert_se(service_unit);
708961c7
MC
74
75 return SERVICE(service_unit);
76}
77
fcb7138c
ZJS
78static int _check_states(unsigned line,
79 Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) {
708961c7
MC
80 assert_se(m);
81 assert_se(service);
bc999297 82
500727c2 83 usec_t end = now(CLOCK_MONOTONIC) + 30 * USEC_PER_SEC;
708961c7 84
75edb0b0
ZJS
85 while (path->state != path_state || service->state != service_state ||
86 path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS) {
bc999297 87
500727c2 88 assert_se(sd_event_run(m->event, 100 * USEC_PER_MSEC) >= 0);
bc999297 89
75edb0b0
ZJS
90 usec_t n = now(CLOCK_MONOTONIC);
91 log_info("line %u: %s: state = %s; result = %s (left: %" PRIi64 ")",
92 line,
93 UNIT(path)->id,
94 path_state_to_string(path->state),
95 path_result_to_string(path->result),
2676befc 96 (int64_t) (end - n));
75edb0b0
ZJS
97 log_info("line %u: %s: state = %s; result = %s",
98 line,
99 UNIT(service)->id,
100 service_state_to_string(service->state),
101 service_result_to_string(service->result));
102
a0b0b670
LB
103 if (service->state == SERVICE_FAILED && service->main_exec_status.status == EXIT_CGROUP) {
104 const char *ci = ci_environment();
105
fcb7138c
ZJS
106 /* On a general purpose system we may fail to start the service for reasons which are
107 * not under our control: permission limits, resource exhaustion, etc. Let's skip the
16e925c6 108 * test in those cases. On developer machines we require proper setup. */
a0b0b670
LB
109 if (!ci)
110 return log_notice_errno(SYNTHETIC_ERRNO(ECANCELED),
111 "Failed to start service %s, aborting test: %s/%s",
112 UNIT(service)->id,
113 service_state_to_string(service->state),
114 service_result_to_string(service->result));
115
116 /* On Salsa we can't setup cgroups so the unit always fails. The test checks if it
117 * can but continues if it cannot at the beginning, but on Salsa it fails here. */
118 if (streq(ci, "salsa-ci"))
119 exit(EXIT_TEST_SKIP);
120 }
fcb7138c 121
75edb0b0 122 if (n >= end) {
708961c7 123 log_error("Test timeout when testing %s", UNIT(path)->id);
bc999297
RC
124 exit(EXIT_FAILURE);
125 }
126 }
fcb7138c
ZJS
127
128 return 0;
bc999297 129}
75edb0b0 130#define check_states(...) _check_states(__LINE__, __VA_ARGS__)
bc999297
RC
131
132static void test_path_exists(Manager *m) {
133 const char *test_path = "/tmp/test-path_exists";
134 Unit *unit = NULL;
708961c7
MC
135 Path *path = NULL;
136 Service *service = NULL;
bc999297
RC
137
138 assert_se(m);
139
ba412430 140 assert_se(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit) >= 0);
708961c7
MC
141
142 path = PATH(unit);
143 service = service_for_path(m, path, NULL);
144
48b92b37 145 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
146 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
147 return;
bc999297
RC
148
149 assert_se(touch(test_path) >= 0);
fcb7138c
ZJS
150 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
151 return;
708961c7
MC
152
153 /* Service restarts if file still exists */
154 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
155 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
156 return;
708961c7
MC
157
158 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
159 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
160 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
161 return;
bc999297 162
708961c7 163 assert_se(unit_stop(unit) >= 0);
bc999297
RC
164}
165
166static void test_path_existsglob(Manager *m) {
167 const char *test_path = "/tmp/test-path_existsglobFOOBAR";
168 Unit *unit = NULL;
708961c7
MC
169 Path *path = NULL;
170 Service *service = NULL;
bc999297
RC
171
172 assert_se(m);
708961c7 173
ba412430 174 assert_se(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit) >= 0);
708961c7
MC
175
176 path = PATH(unit);
177 service = service_for_path(m, path, NULL);
178
48b92b37 179 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
180 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
181 return;
bc999297
RC
182
183 assert_se(touch(test_path) >= 0);
fcb7138c
ZJS
184 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
185 return;
708961c7
MC
186
187 /* Service restarts if file still exists */
188 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
189 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
190 return;
bc999297 191
708961c7
MC
192 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
193 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
194 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
195 return;
708961c7
MC
196
197 assert_se(unit_stop(unit) >= 0);
bc999297
RC
198}
199
200static void test_path_changed(Manager *m) {
201 const char *test_path = "/tmp/test-path_changed";
202 FILE *f;
203 Unit *unit = NULL;
708961c7
MC
204 Path *path = NULL;
205 Service *service = NULL;
bc999297
RC
206
207 assert_se(m);
208
ba412430 209 assert_se(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit) >= 0);
708961c7
MC
210
211 path = PATH(unit);
212 service = service_for_path(m, path, NULL);
213
48b92b37 214 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
215 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
216 return;
708961c7
MC
217
218 assert_se(touch(test_path) >= 0);
fcb7138c
ZJS
219 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
220 return;
708961c7
MC
221
222 /* Service does not restart if file still exists */
223 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
224 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
225 return;
bc999297
RC
226
227 f = fopen(test_path, "w");
228 assert_se(f);
229 fclose(f);
230
fcb7138c
ZJS
231 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
232 return;
708961c7
MC
233
234 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
235 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
236 return;
708961c7
MC
237
238 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
239 assert_se(unit_stop(unit) >= 0);
bc999297
RC
240}
241
242static void test_path_modified(Manager *m) {
243 _cleanup_fclose_ FILE *f = NULL;
244 const char *test_path = "/tmp/test-path_modified";
245 Unit *unit = NULL;
708961c7
MC
246 Path *path = NULL;
247 Service *service = NULL;
bc999297
RC
248
249 assert_se(m);
250
ba412430 251 assert_se(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit) >= 0);
708961c7
MC
252
253 path = PATH(unit);
254 service = service_for_path(m, path, NULL);
255
48b92b37 256 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
257 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
258 return;
708961c7
MC
259
260 assert_se(touch(test_path) >= 0);
fcb7138c
ZJS
261 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
262 return;
708961c7
MC
263
264 /* Service does not restart if file still exists */
265 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
266 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
267 return;
bc999297
RC
268
269 f = fopen(test_path, "w");
270 assert_se(f);
271 fputs("test", f);
272
fcb7138c
ZJS
273 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
274 return;
708961c7
MC
275
276 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
277 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
278 return;
708961c7
MC
279
280 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
281 assert_se(unit_stop(unit) >= 0);
bc999297
RC
282}
283
284static void test_path_unit(Manager *m) {
285 const char *test_path = "/tmp/test-path_unit";
286 Unit *unit = NULL;
708961c7
MC
287 Path *path = NULL;
288 Service *service = NULL;
bc999297
RC
289
290 assert_se(m);
291
ba412430 292 assert_se(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit) >= 0);
708961c7
MC
293
294 path = PATH(unit);
295 service = service_for_path(m, path, "path-mycustomunit.service");
296
48b92b37 297 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
298 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
299 return;
bc999297
RC
300
301 assert_se(touch(test_path) >= 0);
fcb7138c
ZJS
302 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
303 return;
708961c7
MC
304
305 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
306 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
307 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
308 return;
bc999297 309
708961c7 310 assert_se(unit_stop(unit) >= 0);
bc999297
RC
311}
312
313static void test_path_directorynotempty(Manager *m) {
4150584e 314 const char *test_file, *test_path = "/tmp/test-path_directorynotempty/";
bc999297 315 Unit *unit = NULL;
708961c7
MC
316 Path *path = NULL;
317 Service *service = NULL;
bc999297
RC
318
319 assert_se(m);
320
708961c7
MC
321 assert_se(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit) >= 0);
322
323 path = PATH(unit);
324 service = service_for_path(m, path, NULL);
325
bc999297
RC
326 assert_se(access(test_path, F_OK) < 0);
327
48b92b37 328 assert_se(unit_start(unit, NULL) >= 0);
fcb7138c
ZJS
329 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
330 return;
bc999297
RC
331
332 /* MakeDirectory default to no */
333 assert_se(access(test_path, F_OK) < 0);
334
335 assert_se(mkdir_p(test_path, 0755) >= 0);
4150584e
YW
336 test_file = strjoina(test_path, "test_file");
337 assert_se(touch(test_file) >= 0);
fcb7138c
ZJS
338 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
339 return;
708961c7
MC
340
341 /* Service restarts if directory is still not empty */
342 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
343 if (check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING) < 0)
344 return;
708961c7
MC
345
346 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
347 assert_se(unit_stop(UNIT(service)) >= 0);
fcb7138c
ZJS
348 if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
349 return;
bc999297 350
708961c7 351 assert_se(unit_stop(unit) >= 0);
bc999297
RC
352}
353
354static void test_path_makedirectory_directorymode(Manager *m) {
355 const char *test_path = "/tmp/test-path_makedirectory/";
356 Unit *unit = NULL;
357 struct stat s;
358
359 assert_se(m);
360
708961c7
MC
361 assert_se(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit) >= 0);
362
bc999297
RC
363 assert_se(access(test_path, F_OK) < 0);
364
48b92b37 365 assert_se(unit_start(unit, NULL) >= 0);
bc999297
RC
366
367 /* Check if the directory has been created */
368 assert_se(access(test_path, F_OK) >= 0);
369
370 /* Check the mode we specified with DirectoryMode=0744 */
371 assert_se(stat(test_path, &s) >= 0);
372 assert_se((s.st_mode & S_IRWXU) == 0700);
373 assert_se((s.st_mode & S_IRWXG) == 0040);
374 assert_se((s.st_mode & S_IRWXO) == 0004);
375
bd7989a3 376 assert_se(unit_stop(unit) >= 0);
c6878637 377 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
bc999297
RC
378}
379
380int main(int argc, char *argv[]) {
d2120590 381 static const test_function_t tests[] = {
bc999297
RC
382 test_path_exists,
383 test_path_existsglob,
384 test_path_changed,
385 test_path_modified,
386 test_path_unit,
387 test_path_directorynotempty,
388 test_path_makedirectory_directorymode,
389 NULL,
390 };
d2120590 391
55890a40 392 _cleanup_free_ char *test_path = NULL;
e3643b00 393 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
bc999297 394
edb3ca0d
FB
395 umask(022);
396
6d7c4033 397 test_setup_logging(LOG_INFO);
bc999297 398
7b432953 399 assert_se(get_testdata_dir("test-path", &test_path) >= 0);
55890a40 400 assert_se(set_unit_path(test_path) >= 0);
3e29e810 401 assert_se(runtime_dir = setup_fake_runtime_dir());
bc999297 402
c87d0661 403 for (const test_function_t *test = tests; *test; test++) {
e3643b00 404 Manager *m = NULL;
bc999297
RC
405 int r;
406
407 /* We create a clean environment for each test */
408 r = setup_test(&m);
317bb217
ZJS
409 if (r != 0)
410 return r;
bc999297
RC
411
412 (*test)(m);
413
414 shutdown_test(m);
415 }
416
417 return 0;
418}