blob: a38591f3dd9ec37c56462066e8bb75f61d9d5658 [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
334static struct log_info_cat test_categories[] = {
335};
336
337static struct log_info info = {
338 .cat = test_categories,
339 .num_cat = ARRAY_SIZE(test_categories),
340};
341
Max70c7d412017-02-24 13:59:14 +0100342int main(int argc, char **argv)
343{
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200344 ctx = talloc_named_const(NULL, 1, "ctrl_test");
345 osmo_init_logging(&info);
346
Max70c7d412017-02-24 13:59:14 +0100347 printf("Checking ctrl types...\n");
348
349 check_type(CTRL_TYPE_UNKNOWN);
350 check_type(CTRL_TYPE_GET);
351 check_type(CTRL_TYPE_SET);
352 check_type(CTRL_TYPE_GET_REPLY);
353 check_type(CTRL_TYPE_SET_REPLY);
354 check_type(CTRL_TYPE_TRAP);
355 check_type(CTRL_TYPE_ERROR);
356 check_type(64);
357
Neels Hofmeyr83aee832017-12-16 05:38:37 +0100358 test_messages();
Neels Hofmeyr505c9652017-09-26 15:24:58 +0200359
Max70c7d412017-02-24 13:59:14 +0100360 return 0;
361}