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