[MERGED] libosmocore[master]: CTRL: add unit tests for CTRL command parsing

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Wed Sep 27 14:09:34 UTC 2017


Neels Hofmeyr has submitted this change and it was merged.

Change subject: CTRL: add unit tests for CTRL command parsing
......................................................................


CTRL: add unit tests for CTRL command parsing

This uncovers some interesting behavior of the CTRL interface which we may want
to guard against in subsequent patches: trailing whitespace, ignored tokens,
special characters as cmd->id.

Change-Id: If7af06d50ca71fd528b08cd70310774d5a53f0f7
---
M tests/ctrl/ctrl_test.c
M tests/ctrl/ctrl_test.ok
2 files changed, 353 insertions(+), 0 deletions(-)

Approvals:
  Max: Looks good to me, but someone else must approve
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/tests/ctrl/ctrl_test.c b/tests/ctrl/ctrl_test.c
index 08be15f..b8425c7 100644
--- a/tests/ctrl/ctrl_test.c
+++ b/tests/ctrl/ctrl_test.c
@@ -6,6 +6,9 @@
 
 #include <osmocom/core/utils.h>
 #include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/application.h>
 
 static void check_type(enum ctrl_type c)
 {
@@ -19,8 +22,254 @@
 		printf("-> %d %s\n", v, c != v ? "FAIL" : "OK");
 }
 
+struct msgb *msgb_from_string(const char *str)
+{
+	char *rc;
+	size_t len = strlen(str) + 1;
+	/* ctrl_cmd_parse() appends a '\0' to the msgb, allow one more byte. */
+	struct msgb *msg = msgb_alloc(len + 1, str);
+	msg->l2h = msg->head;
+	rc = (char*)msgb_put(msg, len);
+	OSMO_ASSERT(rc == (char*)msg->l2h);
+	strcpy(rc, str);
+	return msg;
+}
+
+static void *ctx = NULL;
+
+void print_escaped(const char *str)
+{
+	if (!str) {
+		printf("NULL");
+		return;
+	}
+
+	printf("'");
+	for (;*str; str++) {
+		switch (*str) {
+		case '\n':
+			printf("\\n");
+			break;
+		case '\r':
+			printf("\\r");
+			break;
+		case '\t':
+			printf("\\t");
+			break;
+		default:
+			printf("%c", *str);
+			break;
+		}
+	}
+	printf("'");
+}
+
+void assert_same_str(const char *label, const char *expect, const char *got)
+{
+	if ((expect == got) || (expect && got && (strcmp(expect, got) == 0))) {
+		printf("%s = ", label);
+		print_escaped(got);
+		printf("\n");
+		return;
+	}
+
+	printf("MISMATCH for '%s':\ngot:      ", label); print_escaped(got);
+	printf("\nexpected: "); print_escaped(expect);
+	printf("\n");
+	OSMO_ASSERT(expect == got);
+}
+
+static void assert_parsing(const char *str, const struct ctrl_cmd *expect)
+{
+	struct ctrl_cmd *cmd;
+	struct msgb *msg = msgb_from_string(str);
+
+	printf("test parsing: ");
+	print_escaped(str);
+	printf("\n");
+
+	cmd = ctrl_cmd_parse(ctx, msg);
+	OSMO_ASSERT(cmd);
+
+	OSMO_ASSERT(expect->type == cmd->type);
+
+#define ASSERT_SAME_STR(field) \
+	assert_same_str(#field, expect->field, cmd->field)
+
+	ASSERT_SAME_STR(id);
+	ASSERT_SAME_STR(variable);
+	ASSERT_SAME_STR(value);
+	ASSERT_SAME_STR(reply);
+
+	talloc_free(cmd);
+	msgb_free(msg);
+
+	printf("ok\n");
+}
+
+struct one_parsing_test {
+	const char *cmd_str;
+	struct ctrl_cmd expect;
+};
+
+static const struct one_parsing_test test_parsing_list[] = {
+	{ "GET 1 variable",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable",
+		}
+	},
+	{ "GET 1 variable\n",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable\n", /* current bug */
+		}
+	},
+	{ "GET 1 var\ni\nable",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "var\ni\nable", /* current bug */
+		}
+	},
+	{ "GET 1 variable value",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable",
+			.value = NULL,
+		}
+	},
+	{ "GET 1 variable value\n",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable",
+			.value = NULL,
+		}
+	},
+	{ "GET 1 variable multiple value tokens",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable",
+			.value = NULL,
+		}
+	},
+	{ "GET 1 variable multiple value tokens\n",
+		{
+			.type = CTRL_TYPE_GET,
+			.id = "1",
+			.variable = "variable",
+			.value = NULL,
+		}
+	},
+	{ "SET 1 variable value",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "value",
+		}
+	},
+	{ "SET 1 variable value\n",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "value",
+		}
+	},
+	{ "SET weird_id variable value",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "weird_id",
+			.variable = "variable",
+			.value = "value",
+		}
+	},
+	{ "SET weird_id variable value\n",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "weird_id",
+			.variable = "variable",
+			.value = "value",
+		}
+	},
+	{ "SET 1 variable multiple value tokens",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "multiple value tokens",
+		}
+	},
+	{ "SET 1 variable multiple value tokens\n",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "multiple value tokens",
+		}
+	},
+	{ "SET 1 variable value_with_trailing_spaces  ",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "value_with_trailing_spaces  ",
+		}
+	},
+	{ "SET 1 variable value_with_trailing_spaces  \n",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "1",
+			.variable = "variable",
+			.value = "value_with_trailing_spaces  ",
+		}
+	},
+	{ "SET \n special_char_id value",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "\n",
+			.variable = "special_char_id",
+			.value = "value",
+		}
+	},
+	{ "SET \t special_char_id value",
+		{
+			.type = CTRL_TYPE_SET,
+			.id = "\t",
+			.variable = "special_char_id",
+			.value = "value",
+		}
+	},
+};
+
+static void test_parsing()
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(test_parsing_list); i++)
+		assert_parsing(test_parsing_list[i].cmd_str,
+			       &test_parsing_list[i].expect);
+}
+
+static struct log_info_cat test_categories[] = {
+};
+
+static struct log_info info = {
+	.cat = test_categories,
+	.num_cat = ARRAY_SIZE(test_categories),
+};
+
 int main(int argc, char **argv)
 {
+	ctx = talloc_named_const(NULL, 1, "ctrl_test");
+	osmo_init_logging(&info);
+
 	printf("Checking ctrl types...\n");
 
 	check_type(CTRL_TYPE_UNKNOWN);
@@ -32,5 +281,7 @@
 	check_type(CTRL_TYPE_ERROR);
 	check_type(64);
 
+	test_parsing();
+
 	return 0;
 }
diff --git a/tests/ctrl/ctrl_test.ok b/tests/ctrl/ctrl_test.ok
index 8f97a27..9c8877b 100644
--- a/tests/ctrl/ctrl_test.ok
+++ b/tests/ctrl/ctrl_test.ok
@@ -7,3 +7,105 @@
 ctrl type 5 is TRAP -> 5 OK
 ctrl type 6 is ERROR -> 6 OK
 ctrl type 64 is unknown 0x40 [PARSE FAILED]
+test parsing: 'GET 1 variable'
+id = '1'
+variable = 'variable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 variable\n'
+id = '1'
+variable = 'variable\n'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 var\ni\nable'
+id = '1'
+variable = 'var\ni\nable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 variable value'
+id = '1'
+variable = 'variable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 variable value\n'
+id = '1'
+variable = 'variable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 variable multiple value tokens'
+id = '1'
+variable = 'variable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'GET 1 variable multiple value tokens\n'
+id = '1'
+variable = 'variable'
+value = NULL
+reply = NULL
+ok
+test parsing: 'SET 1 variable value'
+id = '1'
+variable = 'variable'
+value = 'value'
+reply = NULL
+ok
+test parsing: 'SET 1 variable value\n'
+id = '1'
+variable = 'variable'
+value = 'value'
+reply = NULL
+ok
+test parsing: 'SET weird_id variable value'
+id = 'weird_id'
+variable = 'variable'
+value = 'value'
+reply = NULL
+ok
+test parsing: 'SET weird_id variable value\n'
+id = 'weird_id'
+variable = 'variable'
+value = 'value'
+reply = NULL
+ok
+test parsing: 'SET 1 variable multiple value tokens'
+id = '1'
+variable = 'variable'
+value = 'multiple value tokens'
+reply = NULL
+ok
+test parsing: 'SET 1 variable multiple value tokens\n'
+id = '1'
+variable = 'variable'
+value = 'multiple value tokens'
+reply = NULL
+ok
+test parsing: 'SET 1 variable value_with_trailing_spaces  '
+id = '1'
+variable = 'variable'
+value = 'value_with_trailing_spaces  '
+reply = NULL
+ok
+test parsing: 'SET 1 variable value_with_trailing_spaces  \n'
+id = '1'
+variable = 'variable'
+value = 'value_with_trailing_spaces  '
+reply = NULL
+ok
+test parsing: 'SET \n special_char_id value'
+id = '\n'
+variable = 'special_char_id'
+value = 'value'
+reply = NULL
+ok
+test parsing: 'SET \t special_char_id value'
+id = '\t'
+variable = 'special_char_id'
+value = 'value'
+reply = NULL
+ok

-- 
To view, visit https://gerrit.osmocom.org/4067
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: If7af06d50ca71fd528b08cd70310774d5a53f0f7
Gerrit-PatchSet: 2
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list