]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-name.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / test / test-unit-name.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8 Copyright 2014 Ronny Chevalier
9
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <pwd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "hostname-util.h"
30 #include "macro.h"
31 #include "manager.h"
32 #include "path-util.h"
33 #include "specifier.h"
34 #include "string-util.h"
35 #include "test-helper.h"
36 #include "unit-name.h"
37 #include "unit-printf.h"
38 #include "unit.h"
39 #include "util.h"
40
41 static void test_unit_name_is_valid(void) {
42 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
43 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN));
44 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE));
45 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE));
46 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
47
48 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_ANY));
49 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_PLAIN));
50 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE));
51 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_TEMPLATE));
52 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
53
54 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_ANY));
55 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_PLAIN));
56 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE));
57 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE));
58 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
59
60 assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY));
61 assert_se(!unit_name_is_valid("", UNIT_NAME_ANY));
62 assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY));
63 assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY));
64 assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY));
65 }
66
67 static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) {
68 _cleanup_free_ char *t = NULL;
69 assert_se(unit_name_replace_instance(pattern, repl, &t) == ret);
70 puts(strna(t));
71 assert_se(streq_ptr(t, expected));
72 }
73
74 static void test_u_n_r_i(void) {
75 puts("-------------------------------------------------");
76 test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0);
77 test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0);
78 test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL);
79 test_u_n_r_i_one("", "waldo", NULL, -EINVAL);
80 test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL);
81 test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL);
82 test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL);
83 test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL);
84 }
85
86 static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) {
87 _cleanup_free_ char *t = NULL;
88
89 assert_se(unit_name_from_path(path, suffix, &t) == ret);
90 puts(strna(t));
91 assert_se(streq_ptr(t, expected));
92
93 if (t) {
94 _cleanup_free_ char *k = NULL;
95 assert_se(unit_name_to_path(t, &k) == 0);
96 puts(strna(k));
97 assert_se(path_equal(k, isempty(path) ? "/" : path));
98 }
99 }
100
101 static void test_u_n_f_p(void) {
102 puts("-------------------------------------------------");
103 test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
104 test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
105 test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0);
106 test_u_n_f_p_one("", ".mount", "-.mount", 0);
107 test_u_n_f_p_one("/", ".mount", "-.mount", 0);
108 test_u_n_f_p_one("///", ".mount", "-.mount", 0);
109 test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL);
110 test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL);
111 }
112
113 static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
114 _cleanup_free_ char *t = NULL;
115
116 assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret);
117 puts(strna(t));
118 assert_se(streq_ptr(t, expected));
119
120 if (t) {
121 _cleanup_free_ char *k = NULL, *v = NULL;
122
123 assert_se(unit_name_to_instance(t, &k) > 0);
124 assert_se(unit_name_path_unescape(k, &v) == 0);
125 assert_se(path_equal(v, isempty(path) ? "/" : path));
126 }
127 }
128
129 static void test_u_n_f_p_i(void) {
130 puts("-------------------------------------------------");
131
132 test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0);
133 test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0);
134 test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo@-.mount", 0);
135 test_u_n_f_p_i_one("waldo", "", ".mount", "waldo@-.mount", 0);
136 test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0);
137 test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL);
138 test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL);
139 test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
140 }
141
142 static void test_u_n_t_p_one(const char *unit, const char *path, int ret) {
143 _cleanup_free_ char *p = NULL;
144
145 assert_se(unit_name_to_path(unit, &p) == ret);
146 assert_se(streq_ptr(path, p));
147 }
148
149 static void test_u_n_t_p(void) {
150 test_u_n_t_p_one("home.mount", "/home", 0);
151 test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
152 test_u_n_t_p_one("home-lennart-.mount", NULL, -EINVAL);
153 test_u_n_t_p_one("-home-lennart.mount", NULL, -EINVAL);
154 test_u_n_t_p_one("-home--lennart.mount", NULL, -EINVAL);
155 test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL);
156 test_u_n_t_p_one("", NULL, -EINVAL);
157 test_u_n_t_p_one("home/foo", NULL, -EINVAL);
158 }
159
160 static void test_u_n_m_one(const char *pattern, const char *expect, int ret) {
161 _cleanup_free_ char *t = NULL;
162
163 assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret);
164 puts(strna(t));
165 assert_se(streq_ptr(t, expect));
166
167 if (t) {
168 _cleanup_free_ char *k = NULL;
169
170 assert_se(unit_name_is_valid(t, UNIT_NAME_ANY));
171
172 assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0);
173 assert_se(streq_ptr(t, k));
174 }
175 }
176
177 static void test_u_n_m(void) {
178 puts("-------------------------------------------------");
179 test_u_n_m_one("foo.service", "foo.service", 0);
180 test_u_n_m_one("/home", "home.mount", 1);
181 test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
182 test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
183 test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
184 test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
185 test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
186 test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
187 test_u_n_m_one("", NULL, -EINVAL);
188 }
189
190 static int test_unit_printf(void) {
191 Manager *m = NULL;
192 Unit *u, *u2;
193 int r;
194
195 _cleanup_free_ char *mid, *bid, *host, *root_uid;
196 struct passwd *root;
197
198 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
199 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
200 assert_se((host = gethostname_malloc()));
201
202 assert_se((root = getpwnam("root")));
203 assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0);
204
205 r = manager_new(MANAGER_USER, true, &m);
206 if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
207 puts("manager_new: Permission denied. Skipping test.");
208 return EXIT_TEST_SKIP;
209 }
210 assert_se(r == 0);
211
212 #define expect(unit, pattern, expected) \
213 { \
214 char *e; \
215 _cleanup_free_ char *t = NULL; \
216 assert_se(unit_full_printf(unit, pattern, &t) >= 0); \
217 printf("result: %s\nexpect: %s\n", t, expected); \
218 if ((e = endswith(expected, "*"))) \
219 assert_se(strncmp(t, e, e-expected)); \
220 else \
221 assert_se(streq(t, expected)); \
222 }
223
224 assert_se(setenv("USER", "root", 1) == 0);
225 assert_se(setenv("HOME", "/root", 1) == 0);
226 assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
227
228 assert_se(u = unit_new(m, sizeof(Service)));
229 assert_se(unit_add_name(u, "blah.service") == 0);
230 assert_se(unit_add_name(u, "blah.service") == 0);
231
232 /* general tests */
233 expect(u, "%%", "%");
234 expect(u, "%%s", "%s");
235 expect(u, "%", ""); // REALLY?
236
237 /* normal unit */
238 expect(u, "%n", "blah.service");
239 expect(u, "%f", "/blah");
240 expect(u, "%N", "blah");
241 expect(u, "%p", "blah");
242 expect(u, "%P", "blah");
243 expect(u, "%i", "");
244 expect(u, "%u", root->pw_name);
245 expect(u, "%U", root_uid);
246 expect(u, "%h", root->pw_dir);
247 expect(u, "%m", mid);
248 expect(u, "%b", bid);
249 expect(u, "%H", host);
250 expect(u, "%t", "/run/user/*");
251
252 /* templated */
253 assert_se(u2 = unit_new(m, sizeof(Service)));
254 assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
255 assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
256
257 expect(u2, "%n", "blah@foo-foo.service");
258 expect(u2, "%N", "blah@foo-foo");
259 expect(u2, "%f", "/foo/foo");
260 expect(u2, "%p", "blah");
261 expect(u2, "%P", "blah");
262 expect(u2, "%i", "foo-foo");
263 expect(u2, "%I", "foo/foo");
264 expect(u2, "%u", root->pw_name);
265 expect(u2, "%U", root_uid);
266 expect(u2, "%h", root->pw_dir);
267 expect(u2, "%m", mid);
268 expect(u2, "%b", bid);
269 expect(u2, "%H", host);
270 expect(u2, "%t", "/run/user/*");
271
272 manager_free(m);
273 #undef expect
274
275 return 0;
276 }
277
278 static void test_unit_instance_is_valid(void) {
279 assert_se(unit_instance_is_valid("fooBar"));
280 assert_se(unit_instance_is_valid("foo-bar"));
281 assert_se(unit_instance_is_valid("foo.stUff"));
282 assert_se(unit_instance_is_valid("fOo123.stuff"));
283 assert_se(unit_instance_is_valid("@f_oo123.Stuff"));
284
285 assert_se(!unit_instance_is_valid("$¢£"));
286 assert_se(!unit_instance_is_valid(""));
287 assert_se(!unit_instance_is_valid("foo bar"));
288 assert_se(!unit_instance_is_valid("foo/bar"));
289 }
290
291 static void test_unit_prefix_is_valid(void) {
292 assert_se(unit_prefix_is_valid("fooBar"));
293 assert_se(unit_prefix_is_valid("foo-bar"));
294 assert_se(unit_prefix_is_valid("foo.stUff"));
295 assert_se(unit_prefix_is_valid("fOo123.stuff"));
296 assert_se(unit_prefix_is_valid("foo123.Stuff"));
297
298 assert_se(!unit_prefix_is_valid("$¢£"));
299 assert_se(!unit_prefix_is_valid(""));
300 assert_se(!unit_prefix_is_valid("foo bar"));
301 assert_se(!unit_prefix_is_valid("foo/bar"));
302 assert_se(!unit_prefix_is_valid("@foo-bar"));
303 }
304
305 static void test_unit_name_change_suffix(void) {
306 char *t;
307
308 assert_se(unit_name_change_suffix("foo.mount", ".service", &t) == 0);
309 assert_se(streq(t, "foo.service"));
310 free(t);
311
312 assert_se(unit_name_change_suffix("foo@stuff.service", ".socket", &t) == 0);
313 assert_se(streq(t, "foo@stuff.socket"));
314 free(t);
315 }
316
317 static void test_unit_name_build(void) {
318 char *t;
319
320 assert_se(unit_name_build("foo", "bar", ".service", &t) == 0);
321 assert_se(streq(t, "foo@bar.service"));
322 free(t);
323
324 assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t) == 0);
325 assert_se(streq(t, "fo0-stUff_b@bar.mount"));
326 free(t);
327
328 assert_se(unit_name_build("foo", NULL, ".service", &t) == 0);
329 assert_se(streq(t, "foo.service"));
330 free(t);
331 }
332
333 static void test_slice_name_is_valid(void) {
334 assert_se(slice_name_is_valid("-.slice"));
335 assert_se(slice_name_is_valid("foo.slice"));
336 assert_se(slice_name_is_valid("foo-bar.slice"));
337 assert_se(slice_name_is_valid("foo-bar-baz.slice"));
338 assert_se(!slice_name_is_valid("-foo-bar-baz.slice"));
339 assert_se(!slice_name_is_valid("foo-bar-baz-.slice"));
340 assert_se(!slice_name_is_valid("-foo-bar-baz-.slice"));
341 assert_se(!slice_name_is_valid("foo-bar--baz.slice"));
342 assert_se(!slice_name_is_valid("foo--bar--baz.slice"));
343 assert_se(!slice_name_is_valid(".slice"));
344 assert_se(!slice_name_is_valid(""));
345 assert_se(!slice_name_is_valid("foo.service"));
346 }
347
348 static void test_build_subslice(void) {
349 char *a;
350 char *b;
351
352 assert_se(slice_build_subslice("-.slice", "foo", &a) >= 0);
353 assert_se(slice_build_subslice(a, "bar", &b) >= 0);
354 free(a);
355 assert_se(slice_build_subslice(b, "barfoo", &a) >= 0);
356 free(b);
357 assert_se(slice_build_subslice(a, "foobar", &b) >= 0);
358 free(a);
359 assert_se(streq(b, "foo-bar-barfoo-foobar.slice"));
360 free(b);
361
362 assert_se(slice_build_subslice("foo.service", "bar", &a) < 0);
363 assert_se(slice_build_subslice("foo", "bar", &a) < 0);
364 }
365
366 static void test_build_parent_slice_one(const char *name, const char *expect, int ret) {
367 _cleanup_free_ char *s = NULL;
368
369 assert_se(slice_build_parent_slice(name, &s) == ret);
370 assert_se(streq_ptr(s, expect));
371 }
372
373 static void test_build_parent_slice(void) {
374 test_build_parent_slice_one("-.slice", NULL, 0);
375 test_build_parent_slice_one("foo.slice", "-.slice", 1);
376 test_build_parent_slice_one("foo-bar.slice", "foo.slice", 1);
377 test_build_parent_slice_one("foo-bar-baz.slice", "foo-bar.slice", 1);
378 test_build_parent_slice_one("foo-bar--baz.slice", NULL, -EINVAL);
379 test_build_parent_slice_one("-foo-bar.slice", NULL, -EINVAL);
380 test_build_parent_slice_one("foo-bar-.slice", NULL, -EINVAL);
381 test_build_parent_slice_one("foo-bar.service", NULL, -EINVAL);
382 test_build_parent_slice_one(".slice", NULL, -EINVAL);
383 }
384
385 static void test_unit_name_to_instance(void) {
386 char *instance;
387 int r;
388
389 r = unit_name_to_instance("foo@bar.service", &instance);
390 assert_se(r >= 0);
391 assert_se(streq(instance, "bar"));
392 free(instance);
393
394 r = unit_name_to_instance("foo@.service", &instance);
395 assert_se(r >= 0);
396 assert_se(streq(instance, ""));
397 free(instance);
398
399 r = unit_name_to_instance("fo0-stUff_b@b.service", &instance);
400 assert_se(r >= 0);
401 assert_se(streq(instance, "b"));
402 free(instance);
403
404 r = unit_name_to_instance("foo.service", &instance);
405 assert_se(r == 0);
406 assert_se(!instance);
407
408 r = unit_name_to_instance("fooj@unk", &instance);
409 assert_se(r < 0);
410
411 r = unit_name_to_instance("foo@", &instance);
412 assert_se(r < 0);
413 }
414
415 static void test_unit_name_escape(void) {
416 _cleanup_free_ char *r;
417
418 r = unit_name_escape("ab+-c.a/bc@foo.service");
419 assert_se(r);
420 assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
421 }
422
423
424 static void test_u_n_t_one(const char *name, const char *expected, int ret) {
425 _cleanup_free_ char *f = NULL;
426
427 assert_se(unit_name_template(name, &f) == ret);
428 printf("got: %s, expected: %s\n", strna(f), strna(expected));
429 assert_se(streq_ptr(f, expected));
430 }
431
432 static void test_unit_name_template(void) {
433 test_u_n_t_one("foo@bar.service", "foo@.service", 0);
434 test_u_n_t_one("foo.mount", NULL, -EINVAL);
435 }
436
437 static void test_unit_name_path_unescape_one(const char *name, const char *path, int ret) {
438 _cleanup_free_ char *p = NULL;
439
440 assert_se(unit_name_path_unescape(name, &p) == ret);
441 assert_se(streq_ptr(path, p));
442 }
443
444 static void test_unit_name_path_unescape(void) {
445
446 test_unit_name_path_unescape_one("foo", "/foo", 0);
447 test_unit_name_path_unescape_one("foo-bar", "/foo/bar", 0);
448 test_unit_name_path_unescape_one("foo-.bar", "/foo/.bar", 0);
449 test_unit_name_path_unescape_one("foo-bar-baz", "/foo/bar/baz", 0);
450 test_unit_name_path_unescape_one("-", "/", 0);
451 test_unit_name_path_unescape_one("--", NULL, -EINVAL);
452 test_unit_name_path_unescape_one("-foo-bar", NULL, -EINVAL);
453 test_unit_name_path_unescape_one("foo--bar", NULL, -EINVAL);
454 test_unit_name_path_unescape_one("foo-bar-", NULL, -EINVAL);
455 test_unit_name_path_unescape_one(".-bar", NULL, -EINVAL);
456 test_unit_name_path_unescape_one("foo-..", NULL, -EINVAL);
457 test_unit_name_path_unescape_one("", NULL, -EINVAL);
458 }
459
460 int main(int argc, char* argv[]) {
461 int rc = 0;
462 test_unit_name_is_valid();
463 test_u_n_r_i();
464 test_u_n_f_p();
465 test_u_n_f_p_i();
466 test_u_n_m();
467 test_u_n_t_p();
468 TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf());
469 test_unit_instance_is_valid();
470 test_unit_prefix_is_valid();
471 test_unit_name_change_suffix();
472 test_unit_name_build();
473 test_slice_name_is_valid();
474 test_build_subslice();
475 test_build_parent_slice();
476 test_unit_name_to_instance();
477 test_unit_name_escape();
478 test_unit_name_template();
479 test_unit_name_path_unescape();
480
481 return rc;
482 }