chiark / gitweb /
tests: add more tests for shared/util.c
[elogind.git] / src / test / test-cgroup-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Zbigniew Jędrzejewski-Szmek
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23
24 #include "util.h"
25 #include "cgroup-util.h"
26
27 static void check_p_d_u(const char *path, int code, const char *result) {
28         _cleanup_free_ char *unit = NULL;
29
30         assert_se(cg_path_decode_unit(path, &unit) == code);
31         assert_se(streq_ptr(unit, result));
32 }
33
34 static void test_path_decode_unit(void) {
35         check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
36         check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
37         check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
38         check_p_d_u("getty@.service/", -EINVAL, NULL);
39         check_p_d_u("getty@.service", -EINVAL, NULL);
40         check_p_d_u("getty.service", 0, "getty.service");
41         check_p_d_u("getty", -EINVAL, NULL);
42         check_p_d_u("getty/waldo", -EINVAL, NULL);
43         check_p_d_u("_cpu.service", 0, "cpu.service");
44 }
45
46 static void check_p_g_u(const char *path, int code, const char *result) {
47         _cleanup_free_ char *unit = NULL;
48
49         assert_se(cg_path_get_unit(path, &unit) == code);
50         assert_se(streq_ptr(unit, result));
51 }
52
53 static void test_path_get_unit(void) {
54         check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
55         check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
56         check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
57         check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
58         check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
59         check_p_g_u("sadfdsafsda", -EINVAL, NULL);
60         check_p_g_u("/system.slice/getty####@tty6.service/xxx", -EINVAL, NULL);
61         check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
62         check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
63 }
64
65 static void check_p_g_u_u(const char *path, int code, const char *result) {
66         _cleanup_free_ char *unit = NULL;
67
68         assert_se(cg_path_get_user_unit(path, &unit) == code);
69         assert_se(streq_ptr(unit, result));
70 }
71
72 static void test_path_get_user_unit(void) {
73         check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
74         check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
75         check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
76         check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
77         check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -EINVAL, NULL);
78         check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
79         check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
80         check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
81         check_p_g_u_u("/meh.service", -ENOENT, NULL);
82         check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
83 }
84
85 static void check_p_g_s(const char *path, int code, const char *result) {
86         _cleanup_free_ char *s = NULL;
87
88         assert_se(cg_path_get_session(path, &s) == code);
89         assert_se(streq_ptr(s, result));
90 }
91
92 static void test_path_get_session(void) {
93         check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
94         check_p_g_s("/session-3.scope", 0, "3");
95         check_p_g_s("", -ENOENT, 0);
96 }
97
98 static void check_p_g_o_u(const char *path, int code, uid_t result) {
99         uid_t uid = 0;
100
101         assert_se(cg_path_get_owner_uid(path, &uid) == code);
102         assert_se(uid == result);
103 }
104
105 static void test_path_get_owner_uid(void) {
106         check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
107         check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
108         check_p_g_o_u("", -ENOENT, 0);
109 }
110
111 static void check_p_g_m_n(const char *path, int code, const char *result) {
112         _cleanup_free_ char *m = NULL;
113
114         assert_se(cg_path_get_machine_name(path, &m) == code);
115         assert_se(streq_ptr(m, result));
116 }
117
118 static void test_path_get_machine_name(void) {
119         check_p_g_m_n("/user.slice/machine-foobar.scope", 0, "foobar");
120         check_p_g_m_n("/machine-foobar.scope", 0, "foobar");
121         check_p_g_m_n("/user.slice/user-kuux.slice/machine-foobar.scope", 0, "foobar");
122         check_p_g_m_n("/user.slice/user-kuux.slice/machine-foobar.scope/asjhdkj", 0, "foobar");
123         check_p_g_m_n("", -ENOENT, NULL);
124 }
125
126 static void test_get_paths(void) {
127         _cleanup_free_ char *a = NULL;
128
129         assert_se(cg_get_root_path(&a) >= 0);
130         log_info("Root = %s", a);
131 }
132
133 static void test_proc(void) {
134         _cleanup_closedir_ DIR *d = NULL;
135         struct dirent *de;
136         int r;
137
138         d = opendir("/proc");
139         assert_se(d);
140
141         FOREACH_DIRENT(de, d, break) {
142                 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *prefix = NULL, *slice = NULL;
143                 pid_t pid;
144                 uid_t uid = (uid_t) -1;
145
146                 if (de->d_type != DT_DIR &&
147                     de->d_type != DT_UNKNOWN)
148                         continue;
149
150                 r = parse_pid(de->d_name, &pid);
151                 if (r < 0)
152                         continue;
153
154                 if (is_kernel_thread(pid))
155                         continue;
156
157                 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
158                 cg_pid_get_path_shifted(pid, &prefix, &path_shifted);
159                 cg_pid_get_owner_uid(pid, &uid);
160                 cg_pid_get_session(pid, &session);
161                 cg_pid_get_unit(pid, &unit);
162                 cg_pid_get_user_unit(pid, &user_unit);
163                 cg_pid_get_machine_name(pid, &machine);
164                 cg_pid_get_slice(pid, &slice);
165
166                 printf("%lu\t%s\t%s\t%s\t%lu\t%s\t%s\t%s\t%s\t%s\n",
167                        (unsigned long) pid,
168                        path,
169                        prefix,
170                        path_shifted,
171                        (unsigned long) uid,
172                        session,
173                        unit,
174                        user_unit,
175                        machine,
176                        slice);
177         }
178 }
179
180 static void test_escape_one(const char *s, const char *r) {
181         _cleanup_free_ char *b;
182
183         b = cg_escape(s);
184         assert_se(b);
185         assert_se(streq(b, r));
186
187         assert_se(streq(cg_unescape(b), s));
188 }
189
190 static void test_escape(void) {
191         test_escape_one("foobar", "foobar");
192         test_escape_one(".foobar", "_.foobar");
193         test_escape_one("foobar.service", "foobar.service");
194         test_escape_one("cgroup.service", "_cgroup.service");
195         test_escape_one("cpu.service", "_cpu.service");
196         test_escape_one("tasks", "_tasks");
197         test_escape_one("_foobar", "__foobar");
198         test_escape_one("", "_");
199         test_escape_one("_", "__");
200         test_escape_one(".", "_.");
201 }
202
203 static void test_controller_is_valid(void) {
204         assert_se(cg_controller_is_valid("foobar", false));
205         assert_se(cg_controller_is_valid("foo_bar", false));
206         assert_se(cg_controller_is_valid("name=foo", true));
207         assert_se(!cg_controller_is_valid("", false));
208         assert_se(!cg_controller_is_valid("name=", true));
209         assert_se(!cg_controller_is_valid("=", false));
210         assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
211         assert_se(!cg_controller_is_valid("_", false));
212         assert_se(!cg_controller_is_valid("_foobar", false));
213         assert_se(!cg_controller_is_valid("tatü", false));
214 }
215
216 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
217         _cleanup_free_ char *ret = NULL;
218
219         assert_se(cg_slice_to_path(unit, &ret) == error);
220         assert_se(streq_ptr(ret, path));
221 }
222
223 static void test_slice_to_path(void) {
224
225         test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
226         test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
227         test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
228         test_slice_to_path_one("-.slice", NULL, -EINVAL);
229         test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
230         test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
231         test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
232         test_slice_to_path_one("a-b-c-d-e.slice", "a.slice/a-b.slice/a-b-c.slice/a-b-c-d.slice/a-b-c-d-e.slice", 0);
233 }
234
235 int main(void) {
236         test_path_decode_unit();
237         test_path_get_unit();
238         test_path_get_user_unit();
239         test_path_get_session();
240         test_path_get_owner_uid();
241         test_path_get_machine_name();
242         test_get_paths();
243         test_proc();
244         test_escape();
245         test_controller_is_valid();
246         test_slice_to_path();
247
248         return 0;
249 }