]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-varlink-idl.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / test / test-varlink-idl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <pthread.h>
4
5 #include "fd-util.h"
6 #include "pretty-print.h"
7 #include "tests.h"
8 #include "varlink.h"
9 #include "varlink-idl.h"
10 #include "varlink-io.systemd.h"
11 #include "varlink-io.systemd.Credentials.h"
12 #include "varlink-io.systemd.Journal.h"
13 #include "varlink-io.systemd.ManagedOOM.h"
14 #include "varlink-io.systemd.PCRExtend.h"
15 #include "varlink-io.systemd.Resolve.Monitor.h"
16 #include "varlink-io.systemd.Resolve.h"
17 #include "varlink-io.systemd.UserDatabase.h"
18 #include "varlink-io.systemd.oom.h"
19 #include "varlink-io.systemd.service.h"
20 #include "varlink-io.systemd.sysext.h"
21 #include "varlink-org.varlink.service.h"
22
23 static VARLINK_DEFINE_ENUM_TYPE(
24 EnumTest,
25 VARLINK_DEFINE_ENUM_VALUE(foo),
26 VARLINK_DEFINE_ENUM_VALUE(bar),
27 VARLINK_DEFINE_ENUM_VALUE(baz));
28
29 static VARLINK_DEFINE_STRUCT_TYPE(
30 NestedStructTest,
31 VARLINK_DEFINE_FIELD(x, VARLINK_INT, 0));
32
33 static VARLINK_DEFINE_STRUCT_TYPE(
34 StructTest,
35
36 VARLINK_DEFINE_FIELD(bbb, VARLINK_BOOL, 0),
37 VARLINK_DEFINE_FIELD(bbbn, VARLINK_BOOL, VARLINK_NULLABLE),
38 VARLINK_DEFINE_FIELD(bbba, VARLINK_BOOL, VARLINK_ARRAY),
39 VARLINK_DEFINE_FIELD(bbbna, VARLINK_BOOL, VARLINK_NULLABLE|VARLINK_ARRAY),
40 VARLINK_DEFINE_FIELD(bbbm, VARLINK_BOOL, VARLINK_MAP),
41 VARLINK_DEFINE_FIELD(bbbnm, VARLINK_BOOL, VARLINK_NULLABLE|VARLINK_MAP),
42
43 VARLINK_DEFINE_FIELD(iii, VARLINK_INT, 0),
44 VARLINK_DEFINE_FIELD(iiin, VARLINK_INT, VARLINK_NULLABLE),
45 VARLINK_DEFINE_FIELD(iiia, VARLINK_INT, VARLINK_ARRAY),
46 VARLINK_DEFINE_FIELD(iiina, VARLINK_INT, VARLINK_NULLABLE|VARLINK_ARRAY),
47 VARLINK_DEFINE_FIELD(iiim, VARLINK_INT, VARLINK_MAP),
48 VARLINK_DEFINE_FIELD(iiinm, VARLINK_INT, VARLINK_NULLABLE|VARLINK_MAP),
49
50 VARLINK_DEFINE_FIELD(fff, VARLINK_FLOAT, 0),
51 VARLINK_DEFINE_FIELD(fffn, VARLINK_FLOAT, VARLINK_NULLABLE),
52 VARLINK_DEFINE_FIELD(fffa, VARLINK_FLOAT, VARLINK_ARRAY),
53 VARLINK_DEFINE_FIELD(fffna, VARLINK_FLOAT, VARLINK_NULLABLE|VARLINK_ARRAY),
54 VARLINK_DEFINE_FIELD(fffm, VARLINK_FLOAT, VARLINK_MAP),
55 VARLINK_DEFINE_FIELD(fffnm, VARLINK_FLOAT, VARLINK_NULLABLE|VARLINK_MAP),
56
57 VARLINK_DEFINE_FIELD(sss, VARLINK_STRING, 0),
58 VARLINK_DEFINE_FIELD(sssn, VARLINK_STRING, VARLINK_NULLABLE),
59 VARLINK_DEFINE_FIELD(sssa, VARLINK_STRING, VARLINK_ARRAY),
60 VARLINK_DEFINE_FIELD(sssna, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_ARRAY),
61 VARLINK_DEFINE_FIELD(sssm, VARLINK_STRING, VARLINK_MAP),
62 VARLINK_DEFINE_FIELD(sssnm, VARLINK_STRING, VARLINK_NULLABLE|VARLINK_MAP),
63
64 VARLINK_DEFINE_FIELD(ooo, VARLINK_OBJECT, 0),
65 VARLINK_DEFINE_FIELD(ooon, VARLINK_OBJECT, VARLINK_NULLABLE),
66 VARLINK_DEFINE_FIELD(oooa, VARLINK_OBJECT, VARLINK_ARRAY),
67 VARLINK_DEFINE_FIELD(ooona, VARLINK_OBJECT, VARLINK_NULLABLE|VARLINK_ARRAY),
68 VARLINK_DEFINE_FIELD(ooom, VARLINK_OBJECT, VARLINK_MAP),
69 VARLINK_DEFINE_FIELD(ooonm, VARLINK_OBJECT, VARLINK_NULLABLE|VARLINK_MAP),
70
71 VARLINK_DEFINE_FIELD_BY_TYPE(eee, EnumTest, 0),
72 VARLINK_DEFINE_FIELD_BY_TYPE(eeen, EnumTest, VARLINK_NULLABLE),
73 VARLINK_DEFINE_FIELD_BY_TYPE(eeea, EnumTest, VARLINK_ARRAY),
74 VARLINK_DEFINE_FIELD_BY_TYPE(eeena, EnumTest, VARLINK_NULLABLE|VARLINK_ARRAY),
75 VARLINK_DEFINE_FIELD_BY_TYPE(eeem, EnumTest, VARLINK_MAP),
76 VARLINK_DEFINE_FIELD_BY_TYPE(eeenm, EnumTest, VARLINK_NULLABLE|VARLINK_MAP),
77
78 VARLINK_DEFINE_FIELD_BY_TYPE(nnn, NestedStructTest, 0),
79 VARLINK_DEFINE_FIELD_BY_TYPE(nnnn, NestedStructTest, VARLINK_NULLABLE),
80 VARLINK_DEFINE_FIELD_BY_TYPE(nnna, NestedStructTest, VARLINK_ARRAY),
81 VARLINK_DEFINE_FIELD_BY_TYPE(nnnna, NestedStructTest, VARLINK_NULLABLE|VARLINK_ARRAY),
82 VARLINK_DEFINE_FIELD_BY_TYPE(nnnm, NestedStructTest, VARLINK_MAP),
83 VARLINK_DEFINE_FIELD_BY_TYPE(nnnnm, NestedStructTest, VARLINK_NULLABLE|VARLINK_MAP));
84
85 static VARLINK_DEFINE_METHOD(
86 MethodTest,
87 VARLINK_DEFINE_INPUT(x, VARLINK_BOOL, 0),
88 VARLINK_DEFINE_INPUT_BY_TYPE(y, EnumTest, 0),
89 VARLINK_DEFINE_INPUT_BY_TYPE(z, StructTest, 0),
90 VARLINK_DEFINE_OUTPUT(x, VARLINK_BOOL, 0),
91 VARLINK_DEFINE_OUTPUT_BY_TYPE(y, EnumTest, 0),
92 VARLINK_DEFINE_OUTPUT_BY_TYPE(z, StructTest, 0));
93
94 static VARLINK_DEFINE_ERROR(
95 ErrorTest,
96 VARLINK_DEFINE_FIELD(x, VARLINK_BOOL, 0),
97 VARLINK_DEFINE_FIELD_BY_TYPE(y, EnumTest, 0),
98 VARLINK_DEFINE_FIELD_BY_TYPE(z, StructTest, 0));
99
100 static VARLINK_DEFINE_INTERFACE(
101 xyz_test,
102 "xyz.test",
103 &vl_type_EnumTest,
104 &vl_type_NestedStructTest,
105 &vl_type_StructTest,
106 &vl_method_MethodTest,
107 &vl_error_ErrorTest);
108
109 static void test_parse_format_one(const VarlinkInterface *iface) {
110 _cleanup_(varlink_interface_freep) VarlinkInterface *parsed = NULL;
111 _cleanup_free_ char *text = NULL, *text2 = NULL;
112
113 assert_se(iface);
114
115 assert_se(varlink_idl_dump(stdout, /* use_colors=*/ true, iface) >= 0);
116 assert_se(varlink_idl_consistent(iface, LOG_ERR) >= 0);
117 assert_se(varlink_idl_format(iface, &text) >= 0);
118 assert_se(varlink_idl_parse(text, NULL, NULL, &parsed) >= 0);
119 assert_se(varlink_idl_consistent(parsed, LOG_ERR) >= 0);
120 assert_se(varlink_idl_format(parsed, &text2) >= 0);
121 assert_se(streq(text, text2));
122 }
123
124 TEST(parse_format) {
125 test_parse_format_one(&vl_interface_org_varlink_service);
126 print_separator();
127 test_parse_format_one(&vl_interface_io_systemd_UserDatabase);
128 print_separator();
129 test_parse_format_one(&vl_interface_io_systemd_Journal);
130 print_separator();
131 test_parse_format_one(&vl_interface_io_systemd_Resolve);
132 print_separator();
133 test_parse_format_one(&vl_interface_io_systemd_Resolve_Monitor);
134 print_separator();
135 test_parse_format_one(&vl_interface_io_systemd_ManagedOOM);
136 print_separator();
137 test_parse_format_one(&vl_interface_io_systemd_oom);
138 print_separator();
139 test_parse_format_one(&vl_interface_io_systemd);
140 print_separator();
141 test_parse_format_one(&vl_interface_io_systemd_PCRExtend);
142 print_separator();
143 test_parse_format_one(&vl_interface_io_systemd_service);
144 print_separator();
145 test_parse_format_one(&vl_interface_io_systemd_sysext);
146 print_separator();
147 test_parse_format_one(&vl_interface_io_systemd_Credentials);
148 print_separator();
149 test_parse_format_one(&vl_interface_xyz_test);
150 }
151
152 TEST(parse) {
153 _cleanup_(varlink_interface_freep) VarlinkInterface *parsed = NULL;
154
155 /* This one has (nested) enonymous enums and structs */
156 static const char text[] =
157 "interface quu.waa\n"
158 "type Fooenum ( a, b, c )\n"
159 "type Barstruct ( a : (x, y, z), b : (x : int), c: (f, ff, fff), d: object, e : (sub : (subsub: (subsubsub: string, subsubsub2: (iii, ooo)))))"
160 ;
161
162 assert_se(varlink_idl_parse(text, NULL, NULL, &parsed) >= 0);
163 test_parse_format_one(parsed);
164
165 assert_se(varlink_idl_parse("interface org.freedesktop.Foo\n"
166 "type Foo (b: bool, c: foo, c: int)", NULL, NULL, NULL) == -ENETUNREACH); /* unresolved type */
167 assert_se(varlink_idl_parse("interface org.freedesktop.Foo\n"
168 "type Foo ()", NULL, NULL, NULL) == -EBADMSG); /* empty struct/enum */
169
170 }
171
172 TEST(interface_name_is_valid) {
173 assert_se(!varlink_idl_interface_name_is_valid(NULL));
174 assert_se(!varlink_idl_interface_name_is_valid(""));
175 assert_se(!varlink_idl_interface_name_is_valid(","));
176 assert_se(!varlink_idl_interface_name_is_valid("."));
177 assert_se(!varlink_idl_interface_name_is_valid("-"));
178 assert_se(varlink_idl_interface_name_is_valid("a"));
179 assert_se(varlink_idl_interface_name_is_valid("a.a"));
180 assert_se(!varlink_idl_interface_name_is_valid("-.a"));
181 assert_se(!varlink_idl_interface_name_is_valid("-a.a"));
182 assert_se(!varlink_idl_interface_name_is_valid("a-.a"));
183 assert_se(varlink_idl_interface_name_is_valid("a-a.a"));
184 assert_se(!varlink_idl_interface_name_is_valid("a-a.a-"));
185 assert_se(!varlink_idl_interface_name_is_valid("a-a.-a"));
186 assert_se(!varlink_idl_interface_name_is_valid("a-a.-"));
187 assert_se(varlink_idl_interface_name_is_valid("a-a.a-a"));
188 assert_se(varlink_idl_interface_name_is_valid("io.systemd.Foobar"));
189 }
190
191 TEST(symbol_name_is_valid) {
192 assert_se(!varlink_idl_symbol_name_is_valid(NULL));
193 assert_se(!varlink_idl_symbol_name_is_valid(""));
194 assert_se(!varlink_idl_symbol_name_is_valid("_"));
195 assert_se(!varlink_idl_symbol_name_is_valid("_foo"));
196 assert_se(varlink_idl_symbol_name_is_valid("Foofoo"));
197 assert_se(varlink_idl_symbol_name_is_valid("Foo"));
198 assert_se(varlink_idl_symbol_name_is_valid("Foo0"));
199 assert_se(!varlink_idl_symbol_name_is_valid("0Foo"));
200 assert_se(!varlink_idl_symbol_name_is_valid("foo"));
201 assert_se(varlink_idl_symbol_name_is_valid("Foo0foo"));
202 assert_se(!varlink_idl_symbol_name_is_valid("bool"));
203 assert_se(!varlink_idl_symbol_name_is_valid("int"));
204 assert_se(!varlink_idl_symbol_name_is_valid("float"));
205 assert_se(!varlink_idl_symbol_name_is_valid("string"));
206 assert_se(!varlink_idl_symbol_name_is_valid("object"));
207 }
208
209 TEST(field_name_is_valid) {
210 assert_se(!varlink_idl_field_name_is_valid(NULL));
211 assert_se(!varlink_idl_field_name_is_valid(""));
212 assert_se(!varlink_idl_field_name_is_valid("_"));
213 assert_se(!varlink_idl_field_name_is_valid("_foo"));
214 assert_se(!varlink_idl_field_name_is_valid("_foo_"));
215 assert_se(!varlink_idl_field_name_is_valid("foo_"));
216 assert_se(varlink_idl_field_name_is_valid("foo_foo"));
217 assert_se(varlink_idl_field_name_is_valid("f_o_o_f_o_o"));
218 assert_se(!varlink_idl_field_name_is_valid("foo__foo"));
219 assert_se(varlink_idl_field_name_is_valid("Foofoo"));
220 assert_se(varlink_idl_field_name_is_valid("Foo"));
221 assert_se(varlink_idl_field_name_is_valid("Foo0"));
222 assert_se(!varlink_idl_field_name_is_valid("0Foo"));
223 assert_se(varlink_idl_field_name_is_valid("foo"));
224 assert_se(varlink_idl_field_name_is_valid("Foo0foo"));
225 assert_se(varlink_idl_field_name_is_valid("foo0foo"));
226 }
227
228 TEST(validate_json) {
229
230 _cleanup_(varlink_interface_freep) VarlinkInterface *parsed = NULL;
231
232 /* This one has (nested) enonymous enums and structs */
233 static const char text[] =
234 "interface validate.test\n"
235 "method Mymethod ( a:string, b:int, c:?bool, d:[]int, e:?[string]bool, f:?(piff, paff), g:(f:float) ) -> ()\n";
236
237 assert_se(varlink_idl_parse(text, NULL, NULL, &parsed) >= 0);
238 test_parse_format_one(parsed);
239
240 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
241
242 assert_se(json_build(&v, JSON_BUILD_OBJECT(
243 JSON_BUILD_PAIR("a", JSON_BUILD_STRING("x")),
244 JSON_BUILD_PAIR("b", JSON_BUILD_UNSIGNED(44)),
245 JSON_BUILD_PAIR("d", JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(5), JSON_BUILD_UNSIGNED(7), JSON_BUILD_UNSIGNED(107))),
246 JSON_BUILD_PAIR("g", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("f", JSON_BUILD_REAL(0.5f)))))) >= 0);
247
248 json_variant_dump(v, JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO, stdout, NULL);
249
250 const VarlinkSymbol* symbol = ASSERT_PTR(varlink_idl_find_symbol(parsed, VARLINK_METHOD, "Mymethod"));
251
252 assert_se(varlink_idl_validate_method_call(symbol, v, NULL) >= 0);
253 }
254
255 static int test_recursive_one(unsigned depth) {
256 _cleanup_(varlink_interface_freep) VarlinkInterface *parsed = NULL;
257 _cleanup_free_ char *pre = NULL, *post = NULL, *text = NULL;
258 static const char header[] =
259 "interface recursive.test\n"
260 "type Foo (\n";
261
262 /* Generate a chain of nested structures, i.e. a: (a: (... (int))...) */
263 pre = strrep("a:(", depth);
264 post = strrep(")", depth);
265 if (!pre || !post)
266 return log_oom();
267
268 text = strjoin(header, pre, "int", post, ")");
269 if (!text)
270 return log_oom();
271
272 return varlink_idl_parse(text, NULL, NULL, &parsed);
273 }
274
275 TEST(recursive) {
276 assert_se(test_recursive_one(32) >= 0);
277 assert_se(test_recursive_one(64) >= 0);
278
279 /* We should handle this gracefully without a stack overflow */
280 assert_se(test_recursive_one(65) < 0);
281 assert_se(test_recursive_one(20000) < 0 );
282 }
283
284 static int test_method(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
285 JsonVariant *foo = json_variant_by_key(parameters, "foo"), *bar = json_variant_by_key(parameters, "bar");
286
287 return varlink_replyb(link,
288 JSON_BUILD_OBJECT(
289 JSON_BUILD_PAIR_UNSIGNED("waldo", json_variant_unsigned(foo) * json_variant_unsigned(bar)),
290 JSON_BUILD_PAIR_UNSIGNED("quux", json_variant_unsigned(foo) + json_variant_unsigned(bar))));
291 }
292
293 static int done_method(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
294 assert_se(sd_event_exit(varlink_get_event(link), 0) >= 0);
295 return 0;
296 }
297
298 static VARLINK_DEFINE_METHOD(
299 TestMethod,
300 VARLINK_DEFINE_INPUT(foo, VARLINK_INT, 0),
301 VARLINK_DEFINE_INPUT(bar, VARLINK_INT, 0),
302 VARLINK_DEFINE_INPUT(optional, VARLINK_STRING, VARLINK_NULLABLE),
303 VARLINK_DEFINE_OUTPUT(waldo, VARLINK_INT, 0),
304 VARLINK_DEFINE_OUTPUT(quux, VARLINK_INT, 0));
305
306 static VARLINK_DEFINE_METHOD(Done);
307
308 static VARLINK_DEFINE_INTERFACE(
309 xyz,
310 "xyz",
311 &vl_method_TestMethod,
312 &vl_method_Done);
313
314
315 static void* server_thread(void *userdata) {
316 _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
317 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
318
319 assert_se(varlink_server_new(&server, 0) >= 0);
320 assert_se(varlink_server_add_interface(server, &vl_interface_xyz) >= 0);
321 assert_se(varlink_server_bind_method(server, "xyz.TestMethod", test_method) >= 0);
322 assert_se(varlink_server_bind_method(server, "xyz.Done", done_method) >= 0);
323
324 assert_se(sd_event_new(&event) >= 0);
325 assert_se(varlink_server_attach_event(server, event, 0) >= 0);
326
327 assert_se(varlink_server_add_connection(server, PTR_TO_FD(userdata), NULL) >= 0);
328
329 assert_se(sd_event_loop(event) >= 0);
330 return NULL;
331 }
332
333 TEST(validate_method_call) {
334 _cleanup_close_pair_ int fd[2] = EBADF_PAIR;
335 _cleanup_(varlink_unrefp) Varlink *v = NULL;
336 pthread_t t;
337
338 assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0, fd) >= 0);
339 assert_se(pthread_create(&t, NULL, server_thread, FD_TO_PTR(TAKE_FD(fd[1]))) == 0);
340 assert_se(varlink_connect_fd(&v, TAKE_FD(fd[0])) >= 0);
341
342 JsonVariant *reply = NULL;
343 const char *error_id = NULL;
344 assert_se(varlink_callb(v, "xyz.TestMethod", &reply, &error_id, NULL,
345 JSON_BUILD_OBJECT(
346 JSON_BUILD_PAIR_UNSIGNED("foo", 8),
347 JSON_BUILD_PAIR_UNSIGNED("bar", 9))) >= 0);
348
349 _cleanup_(json_variant_unrefp) JsonVariant *expected_reply = NULL;
350 assert_se(json_build(&expected_reply,
351 JSON_BUILD_OBJECT(
352 JSON_BUILD_PAIR_UNSIGNED("waldo", 8*9),
353 JSON_BUILD_PAIR_UNSIGNED("quux", 8+9))) >= 0);
354
355 assert_se(!error_id);
356
357 json_variant_dump(reply, JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO, NULL, NULL);
358 json_variant_dump(expected_reply, JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO, NULL, NULL);
359 assert_se(json_variant_equal(reply, expected_reply));
360
361 assert_se(varlink_callb(v, "xyz.TestMethod", &reply, &error_id, NULL,
362 JSON_BUILD_OBJECT(
363 JSON_BUILD_PAIR_UNSIGNED("foo", 9),
364 JSON_BUILD_PAIR_UNSIGNED("bar", 8),
365 JSON_BUILD_PAIR_STRING("optional", "pfft"))) >= 0);
366
367 assert_se(!error_id);
368 assert_se(json_variant_equal(reply, expected_reply));
369
370 assert_se(varlink_callb(v, "xyz.TestMethod", &reply, &error_id, NULL,
371 JSON_BUILD_OBJECT(
372 JSON_BUILD_PAIR_UNSIGNED("foo", 8),
373 JSON_BUILD_PAIR_UNSIGNED("bar", 9),
374 JSON_BUILD_PAIR_STRING("zzz", "pfft"))) >= 0);
375 assert_se(streq_ptr(error_id, VARLINK_ERROR_INVALID_PARAMETER));
376
377 assert_se(varlink_callb(v, "xyz.TestMethod", &reply, &error_id, NULL,
378 JSON_BUILD_OBJECT(
379 JSON_BUILD_PAIR_STRING("foo", "wuff"),
380 JSON_BUILD_PAIR_UNSIGNED("bar", 9))) >= 0);
381 assert_se(streq_ptr(error_id, VARLINK_ERROR_INVALID_PARAMETER));
382
383 assert_se(varlink_send(v, "xyz.Done", NULL) >= 0);
384 assert_se(varlink_flush(v) >= 0);
385 assert_se(pthread_join(t, NULL) == 0);
386 }
387
388 DEFINE_TEST_MAIN(LOG_DEBUG);