blob: 8bb917b9d1e3b6a84e6a1e0db09f5a8ee26f20ed [file] [log] [blame]
Max70c7d412017-02-24 13:59:14 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <stdint.h>
4#include <string.h>
5#include <stdbool.h>
6
7#include <osmocom/core/utils.h>
8#include <osmocom/ctrl/control_cmd.h>
Neels Hofmeyr505c9652017-09-26 15:24:58 +02009#include <osmocom/core/logging.h>
10#include <osmocom/core/msgb.h>
11#include <osmocom/core/application.h>
Neels Hofmeyr83aee832017-12-16 05:38:37 +010012#include <osmocom/gsm/protocol/ipaccess.h>
13#include <osmocom/ctrl/control_if.h>
Max70c7d412017-02-24 13:59:14 +010014
Vadim Yanitskiyc2afe812017-06-13 01:43:23 +070015static void check_type(enum ctrl_type c)
Max70c7d412017-02-24 13:59:14 +010016{
17 const char *t = get_value_string(ctrl_type_vals, c);
18 int v = get_string_value(ctrl_type_vals, t);
19
20 printf("ctrl type %d is %s ", c, t);
21 if (v < 0)
22 printf("[PARSE FAILED]\n");
23 else
24 printf("-> %d %s\n", v, c != v ? "FAIL" : "OK");
25}
26
Neels Hofmeyr505c9652017-09-26 15:24:58 +020027struct msgb *msgb_from_string(const char *str)
28{
Neels Hofmeyr83aee832017-12-16 05:38:37 +010029 struct ipaccess_head *iph;
30 struct ipaccess_head_ext *ipx;
31 char *str_msg;
Neels Hofmeyr505c9652017-09-26 15:24:58 +020032 size_t len = strlen(str) + 1;
Neels Hofmeyr83aee832017-12-16 05:38:37 +010033
34 struct msgb *msg = msgb_alloc(1024, str);
35
36 iph = (void*)msgb_put(msg, sizeof(*iph));
37 iph->proto = IPAC_PROTO_OSMO;
38
39 ipx = (void*)msgb_put(msg, sizeof(*ipx));
40 ipx->proto = IPAC_PROTO_EXT_CTRL;
41
42 str_msg = (char*)msgb_put(msg, len);
43 msg->l2h = (void*)str_msg;
44 osmo_strlcpy(str_msg, str, len);
45
46 iph->len = msgb_length(msg);
Neels Hofmeyr505c9652017-09-26 15:24:58 +020047 return msg;
48}
49
50static void *ctx = NULL;
51
Neels Hofmeyr83aee832017-12-16 05:38:37 +010052struct one_test {
53 const char *cmd_str;
54 struct ctrl_cmd expect_parsed;
55 const char *reply_str;
56};
57
Neels Hofmeyr505c9652017-09-26 15:24:58 +020058void assert_same_str(const char *label, const char *expect, const char *got)
59{
60 if ((expect == got) || (expect && got && (strcmp(expect, got) == 0))) {
Neels Hofmeyr0ab6eca2017-12-16 01:03:37 +010061 printf("%s = '%s'\n", label, osmo_escape_str(got, -1));
Neels Hofmeyr505c9652017-09-26 15:24:58 +020062 return;
63 }
64
Neels Hofmeyr0ab6eca2017-12-16 01:03:37 +010065 printf("MISMATCH for '%s':\ngot: %s\n", label, osmo_escape_str(got, -1));
66 printf("expected: %s\n", osmo_escape_str(expect, -1));
Neels Hofmeyr505c9652017-09-26 15:24:58 +020067 OSMO_ASSERT(expect == got);
68}
69
Neels Hofmeyr83aee832017-12-16 05:38:37 +010070static void assert_test(struct ctrl_handle *ctrl, struct ctrl_connection *ccon, const struct one_test *t)
Neels Hofmeyr505c9652017-09-26 15:24:58 +020071{
72 struct ctrl_cmd *cmd;
Neels Hofmeyr83aee832017-12-16 05:38:37 +010073 struct msgb *msg = msgb_from_string(t->cmd_str);
74 int ctx_size_was;
Neels Hofmeyr505c9652017-09-26 15:24:58 +020075
Neels Hofmeyr83aee832017-12-16 05:38:37 +010076 printf("test: '%s'\n", osmo_escape_str(t->cmd_str, -1));
77 printf("parsing:\n");
Neels Hofmeyr505c9652017-09-26 15:24:58 +020078
Neels Hofmeyrc0b0b622017-12-16 01:12:35 +010079 cmd = ctrl_cmd_parse2(ctx, msg);
Neels Hofmeyr505c9652017-09-26 15:24:58 +020080 OSMO_ASSERT(cmd);
81
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +020082 if (t->expect_parsed.type != cmd->type) {
83 printf("type mismatch: got %s\n", get_value_string(ctrl_type_vals, cmd->type));
84 OSMO_ASSERT(t->expect_parsed.type == cmd->type);
85 }
Neels Hofmeyr505c9652017-09-26 15:24:58 +020086
87#define ASSERT_SAME_STR(field) \
Neels Hofmeyr83aee832017-12-16 05:38:37 +010088 assert_same_str(#field, t->expect_parsed.field, cmd->field)
Neels Hofmeyr505c9652017-09-26 15:24:58 +020089
90 ASSERT_SAME_STR(id);
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +020091 if (t->expect_parsed.type != CTRL_TYPE_ERROR) {
92 ASSERT_SAME_STR(variable);
93 ASSERT_SAME_STR(value);
94 }
Neels Hofmeyr505c9652017-09-26 15:24:58 +020095 ASSERT_SAME_STR(reply);
96
97 talloc_free(cmd);
98 msgb_free(msg);
99
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100100 printf("handling:\n");
101
102 ctx_size_was = talloc_total_size(ctx);
103
104 msg = msgb_from_string(t->cmd_str);
105 ctrl_handle_msg(ctrl, ccon, msg);
106
107 if (llist_empty(&ccon->write_queue.msg_queue)) {
108 if (t->reply_str) {
109 printf("Got no reply, but expected \"%s\"\n", osmo_escape_str(t->reply_str, -1));
110 OSMO_ASSERT(!t->reply_str);
111 }
112 } else {
113 struct msgb *sent_msg = msgb_dequeue(&ccon->write_queue.msg_queue);
114 OSMO_ASSERT(sent_msg);
115 msgb_put_u8(sent_msg, 0);
116
117 printf("replied: '%s'\n", osmo_escape_str((char*)msgb_l2(sent_msg), -1));
118 OSMO_ASSERT(t->reply_str);
119 OSMO_ASSERT(!strcmp(t->reply_str, (char*)msgb_l2(sent_msg)))
120 msgb_free(sent_msg);
121 }
122 osmo_wqueue_clear(&ccon->write_queue);
123
124 msgb_free(msg);
125
126 if (talloc_total_size(ctx) != ctx_size_was) {
127 printf("mem leak!\n");
Neels Hofmeyrf2c10f12017-12-16 04:05:21 +0100128 talloc_report_full(ctx, stdout);
129 OSMO_ASSERT(false);
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100130 }
131
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200132 printf("ok\n");
133}
134
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100135static const struct one_test test_messages_list[] = {
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200136 { "GET 1 variable",
137 {
138 .type = CTRL_TYPE_GET,
139 .id = "1",
140 .variable = "variable",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100141 },
142 "ERROR 1 Command not found",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200143 },
144 { "GET 1 variable\n",
145 {
146 .type = CTRL_TYPE_GET,
147 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200148 .variable = "variable",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100149 },
150 "ERROR 1 Command not found",
151
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200152 },
153 { "GET 1 var\ni\nable",
154 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200155 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200156 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200157 .reply = "GET with trailing characters",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100158 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200159 "ERROR 1 GET with trailing characters",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200160 },
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100161 { "GET 1 var\ti\table",
162 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200163 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100164 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200165 .reply = "GET variable contains invalid characters",
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100166 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200167 "ERROR 1 GET variable contains invalid characters",
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100168 },
169 { "GET 1 var\ri\rable",
170 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200171 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100172 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200173 .reply = "GET variable contains invalid characters",
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100174 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200175 "ERROR 1 GET variable contains invalid characters",
Neels Hofmeyr1b8b1522017-12-15 20:41:28 +0100176 },
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200177 { "GET 1 variable value",
178 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200179 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200180 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200181 .reply = "GET with trailing characters",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100182 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200183 "ERROR 1 GET with trailing characters",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200184 },
185 { "GET 1 variable value\n",
186 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200187 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200188 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200189 .reply = "GET with trailing characters",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100190 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200191 "ERROR 1 GET with trailing characters",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200192 },
193 { "GET 1 variable multiple value tokens",
194 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200195 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200196 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200197 .reply = "GET with trailing characters",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100198 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200199 "ERROR 1 GET with trailing characters",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200200 },
201 { "GET 1 variable multiple value tokens\n",
202 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200203 .type = CTRL_TYPE_ERROR,
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200204 .id = "1",
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200205 .reply = "GET with trailing characters",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100206 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200207 "ERROR 1 GET with trailing characters",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200208 },
209 { "SET 1 variable value",
210 {
211 .type = CTRL_TYPE_SET,
212 .id = "1",
213 .variable = "variable",
214 .value = "value",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100215 },
216 "ERROR 1 Command not found",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200217 },
218 { "SET 1 variable value\n",
219 {
220 .type = CTRL_TYPE_SET,
221 .id = "1",
222 .variable = "variable",
223 .value = "value",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100224 },
225 "ERROR 1 Command not found",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200226 },
227 { "SET weird_id variable value",
228 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200229 .type = CTRL_TYPE_ERROR,
230 .id = "err",
231 .reply = "Invalid message ID number",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100232 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200233 "ERROR err Invalid message ID number",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200234 },
235 { "SET weird_id variable value\n",
236 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200237 .type = CTRL_TYPE_ERROR,
238 .id = "err",
239 .reply = "Invalid message ID number",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100240 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200241 "ERROR err Invalid message ID number",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200242 },
243 { "SET 1 variable multiple value tokens",
244 {
245 .type = CTRL_TYPE_SET,
246 .id = "1",
247 .variable = "variable",
248 .value = "multiple value tokens",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100249 },
250 "ERROR 1 Command not found",
251
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200252 },
253 { "SET 1 variable multiple value tokens\n",
254 {
255 .type = CTRL_TYPE_SET,
256 .id = "1",
257 .variable = "variable",
258 .value = "multiple value tokens",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100259 },
260 "ERROR 1 Command not found",
261
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200262 },
263 { "SET 1 variable value_with_trailing_spaces ",
264 {
265 .type = CTRL_TYPE_SET,
266 .id = "1",
267 .variable = "variable",
268 .value = "value_with_trailing_spaces ",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100269 },
270 "ERROR 1 Command not found",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200271 },
272 { "SET 1 variable value_with_trailing_spaces \n",
273 {
274 .type = CTRL_TYPE_SET,
275 .id = "1",
276 .variable = "variable",
277 .value = "value_with_trailing_spaces ",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100278 },
279 "ERROR 1 Command not found",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200280 },
281 { "SET \n special_char_id value",
282 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200283 .type = CTRL_TYPE_ERROR,
284 .id = "err",
285 .reply = "Invalid message ID number",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100286 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200287 "ERROR err Invalid message ID number",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200288 },
289 { "SET \t special_char_id value",
290 {
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200291 .type = CTRL_TYPE_ERROR,
292 .id = "err",
293 .reply = "Invalid message ID number",
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100294 },
Neels Hofmeyr3da9aa62017-09-26 14:21:44 +0200295 "ERROR err Invalid message ID number",
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200296 },
Neels Hofmeyr6769ad62017-12-16 04:01:54 +0100297 { "GET_REPLY 1 variable OK",
298 {
299 .type = CTRL_TYPE_GET_REPLY,
300 .id = "1",
301 .variable = "variable",
302 .reply = "OK",
303 },
Neels Hofmeyr6769ad62017-12-16 04:01:54 +0100304 },
305 { "SET_REPLY 1 variable OK",
306 {
307 .type = CTRL_TYPE_SET_REPLY,
308 .id = "1",
309 .variable = "variable",
310 .reply = "OK",
311 },
Neels Hofmeyr6769ad62017-12-16 04:01:54 +0100312 },
313
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200314};
315
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100316static void test_messages()
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200317{
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100318 struct ctrl_handle *ctrl;
319 struct ctrl_connection *ccon;
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200320 int i;
321
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100322 ctrl = ctrl_handle_alloc2(ctx, NULL, NULL, 0);
323 ccon = talloc_zero(ctx, struct ctrl_connection);
324
325 osmo_wqueue_init(&ccon->write_queue, 1);
326
327 for (i = 0; i < ARRAY_SIZE(test_messages_list); i++)
328 assert_test(ctrl, ccon, &test_messages_list[i]);
329
330 talloc_free(ccon);
331 talloc_free(ctrl);
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200332}
333
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200334CTRL_CMD_DEFINE(test_defer, "test-defer");
335static void ctrl_test_defer_cb(void *data)
336{
337 struct ctrl_cmd_def *cd = data;
338 struct ctrl_cmd *cmd = cd->cmd;
339 static int i = 0;
340 printf("%s called\n", __func__);
341
342 if (ctrl_cmd_def_is_zombie(cd)) {
343 printf("Is Zombie\n");
344 return;
345 }
346
347 cmd->reply = talloc_asprintf(cmd, "Test Defer #%d", i++);
348
349 ctrl_cmd_def_send(cd);
350 return;
351}
352
353static struct ctrl_cmd_def *test_defer_cd = NULL;
354static int get_test_defer(struct ctrl_cmd *cmd, void *data)
355{
356 void *ctx = cmd->node;
357 printf("%s called\n", __func__);
358
359 test_defer_cd = ctrl_cmd_def_make(ctx, cmd, NULL, 10);
360
361 return CTRL_CMD_HANDLED;
362}
363static int set_test_defer(struct ctrl_cmd *cmd, void *data)
364{
365 return CTRL_CMD_HANDLED;
366}
367static int verify_test_defer(struct ctrl_cmd *cmd, const char *value, void *data)
368{
369 return 0;
370}
371
372static void test_deferred_cmd()
373{
374 struct ctrl_handle *ctrl;
375 struct ctrl_connection *ccon;
376 struct msgb *msg;
377 int result;
378 int ctx_size_was;
379 int ctx_size_before_defer;
380
381 printf("\n%s\n", __func__);
382 ctx_size_was = talloc_total_size(ctx);
383
384 ctrl = ctrl_handle_alloc2(ctx, NULL, NULL, 0);
385 ccon = talloc_zero(ctx, struct ctrl_connection);
386 INIT_LLIST_HEAD(&ccon->def_cmds);
387
388 osmo_wqueue_init(&ccon->write_queue, 1);
389
390 ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_test_defer);
391
392 ctx_size_before_defer = talloc_total_size(ctx);
393
394 msg = msgb_from_string("GET 123 test-defer");
395
396 result = ctrl_handle_msg(ctrl, ccon, msg);
397 printf("ctrl_handle_msg() returned %d\n", result);
398
399 OSMO_ASSERT(result == CTRL_CMD_HANDLED);
Neels Hofmeyra8b6cc42018-04-05 18:11:08 +0200400 talloc_free(msg);
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200401
402 /* Expecting a ctrl_cmd_def as well as the cmd to still be allocated */
403 if (talloc_total_size(ctx) <= ctx_size_before_defer) {
404 printf("deferred command apparently deallocated too soon\n");
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200405 talloc_report_full(ctx, stdout);
406 OSMO_ASSERT(false);
407 }
408
409 printf("invoking ctrl_test_defer_cb() asynchronously\n");
410 ctrl_test_defer_cb(test_defer_cd);
411
Neels Hofmeyra8b6cc42018-04-05 18:11:08 +0200412 /* simulate sending of the reply */
413 osmo_wqueue_clear(&ccon->write_queue);
414
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200415 /* And now the deferred cmd should be cleaned up completely. */
416 if (talloc_total_size(ctx) != ctx_size_before_defer) {
417 printf("mem leak!\n");
418 talloc_report_full(ctx, stdout);
419 OSMO_ASSERT(false);
420 }
421
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200422 talloc_free(ccon);
423 talloc_free(ctrl);
424
425 if (talloc_total_size(ctx) != ctx_size_was) {
426 printf("mem leak!\n");
427 talloc_report_full(ctx, stdout);
428 OSMO_ASSERT(false);
429 }
430
431 printf("success\n");
432}
433
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200434static struct log_info_cat test_categories[] = {
435};
436
437static struct log_info info = {
438 .cat = test_categories,
439 .num_cat = ARRAY_SIZE(test_categories),
440};
441
Max70c7d412017-02-24 13:59:14 +0100442int main(int argc, char **argv)
443{
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200444 ctx = talloc_named_const(NULL, 1, "ctrl_test");
Neels Hofmeyra8b6cc42018-04-05 18:11:08 +0200445 osmo_init_logging2(ctx, &info);
446 msgb_talloc_ctx_init(ctx, 0);
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200447
Max70c7d412017-02-24 13:59:14 +0100448 printf("Checking ctrl types...\n");
449
450 check_type(CTRL_TYPE_UNKNOWN);
451 check_type(CTRL_TYPE_GET);
452 check_type(CTRL_TYPE_SET);
453 check_type(CTRL_TYPE_GET_REPLY);
454 check_type(CTRL_TYPE_SET_REPLY);
455 check_type(CTRL_TYPE_TRAP);
456 check_type(CTRL_TYPE_ERROR);
457 check_type(64);
458
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100459 test_messages();
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200460
Neels Hofmeyr6882b802018-04-05 02:14:12 +0200461 test_deferred_cmd();
462
Neels Hofmeyra8b6cc42018-04-05 18:11:08 +0200463 /* Expecting root ctx + msgb root ctx + 5 logging elements */
464 if (talloc_total_blocks(ctx) != 7) {
465 talloc_report_full(ctx, stdout);
466 OSMO_ASSERT(false);
467 }
468
Max70c7d412017-02-24 13:59:14 +0100469 return 0;
470}