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