test_template_compile: new unit test implemented. Main goal of this test is to help the refactoring the log_template_compile monster function Signed-off-by: Juhasz Viktor <jviktor@balabit.hu> --- tests/unit/Makefile.am | 5 + tests/unit/test_template_compile.c | 320 ++++++++++++++++++++++++++++++++++++ 2 files changed, 325 insertions(+) diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 8841834..af5730f 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -8,6 +8,7 @@ tests_unit_TESTS = \ tests/unit/test_serialize \ tests/unit/test_msgparse \ tests/unit/test_template \ + tests/unit/test_template_compile \ tests/unit/test_template_speed \ tests/unit/test_dnscache \ tests/unit/test_findcrlf \ @@ -56,6 +57,10 @@ tests_unit_test_template_LDADD = \ $(unit_test_extra_modules) \ $(PREOPEN_BASICFUNCS) +tests_unit_test_template_compile_CFLAGS = $(TEST_CFLAGS) +tests_unit_test_template_compile_LDADD = \ + $(TEST_LDADD) $(unit_test_extra_modules) + tests_unit_test_template_speed_LDADD = \ $(TEST_LDADD) $(unit_test_extra_modules) diff --git a/tests/unit/test_template_compile.c b/tests/unit/test_template_compile.c new file mode 100644 index 0000000..23fed4f --- /dev/null +++ b/tests/unit/test_template_compile.c @@ -0,0 +1,320 @@ +#include "templates.c" +#include "logmsg.h" +#include "testutils.h" +#include "cfg.h" +#include "plugin.h" + +#define SIMPLE_STRING "Test String" +#define SIMPLE_MACRO "${MESSAGE}" +#define SIMPLE_MACRO_UNBRACE "$MESSAGE" +#define SIMPLE_MACRO_UNBRACE_ADD_TEXT "$MESSAGE test value" +#define SIMPLE_MACRO_MSGREF "${MESSAGE}@1" +#define SIMPLE_MACRO_INVALID_REF "${MESSAGE}@gmail.com" +#define SIMPLE_MACRO_ADD_TEXT "${MESSAGE}test value" +#define ESCAPED_CHAR "Test \\$STRING" +#define VALID_SUBST "${MESSAGE:-default value}" +#define TRICKY_VALUE "$$VALUE_NAME" +#define TRICKY_VALUE_2 "$:VALUE_NAME" +#define TRICKY_VALUE_3 "$${VALUE_NAME}" +#define TRICKY_VALUE_4 "\\" +#define TRICKY_VALUE_5 "$" +#define TRICKY_VALUE_6 "${MESSAGE:-}" +#define TRICKY_VALUE_7 "${}" + +#define INVALID_MACRO "${MESSAGE" +#define INVALID_SUBST "${MESSAGE:1}" + +#define SIMPLE_VALUE "${VALUE_NAME}" +#define SIMPLE_VALUE_UNBRACE "$VALUE_NAME" +#define SIMPLE_VALUE_ESCAPED "${VALUE\\}NAME}" + +#define SIMPLE_TEMPLATE_FUNCTION "$(hello)" +#define SIMPLE_TEMPLATE_FUNCTION_WITH_ADDITIONAL_TEXT "$(hello)test value" +#define COMPLICATED_TEMPLATE_FUNCTION "$( hello \\tes\t\t\t value(xyz) \"value with spaces\" 'test value with spa\"ces')@2" +#define COMPLICATED_TEMPLATE_FUNCTION_BAD_1 "$( hello \\tes\t\t\t value(xyz \"value with spaces\" 'test value with spa\"ces')" +#define COMPLICATED_TEMPLATE_FUNCTION_BAD_2 "$( hello \\tes\t\t\t value xyz \"value with spaces\" 'test value with spa\"ces'" + +#define SIMPLE_UNKNOWN_FUNCTION "$(unknown function)" + +static void +hello(LogMessage *msg, int argc, GString *argv[], GString *result) +{ + return; +} + +TEMPLATE_FUNCTION_SIMPLE(hello); +Plugin hello_plugin = TEMPLATE_FUNCTION_PLUGIN(hello, "hello"); + + +GlobalConfig *configuration; +static void +hide_internal_message(LogMessage *msg) +{ + log_msg_unref(msg); + return; +} + +#define assert_common_element(actual, expected) \ + assert_string(actual.text, expected.text, ASSERTION_ERROR("Bad compiled template text")); \ + if (expected.default_value) \ + { \ + assert_string(actual.default_value, expected.default_value, ASSERTION_ERROR("Bad compiled template default value")); \ + } \ + else \ + { \ + assert_gpointer(actual.default_value, NULL, ASSERTION_ERROR("Bad compiled template default value")); \ + } \ + assert_gint(actual.msg_ref, expected.msg_ref, ASSERTION_ERROR("Bad compiled template msg_ref")); + +#define assert_value_element(actual, expected) \ + assert_gint(actual.type, LTE_VALUE, ASSERTION_ERROR("Bad compiled template type")); \ + assert_common_element(actual, expected); \ + assert_gint(actual.value_handle, expected.value_handle, ASSERTION_ERROR("Bad compiled template macro")); + +#define assert_macro_element(actual, expected) \ + assert_gint(actual.type, LTE_MACRO, ASSERTION_ERROR("Bad compiled template type")); \ + assert_common_element(actual, expected); \ + assert_gint(actual.macro, expected.macro, ASSERTION_ERROR("Bad compiled template macro")); + +#define assert_func_element(actual, expected) \ + assert_gint(actual.type, LTE_FUNC, ASSERTION_ERROR("Bad compiled template type")); \ + assert_common_element(actual, expected); \ + assert_gpointer(actual.func.ops, expected.func.ops, ASSERTION_ERROR("Bad compiled template macro")); + +#define assert_bad_element(actual, expected, expected_error_message) \ + assert_string(err->message, expected_error_message, ASSERTION_ERROR("Bad error message")); \ + assert_macro_element(actual, expected) + + +#define assert_template_compile(template_string) \ + assert_true(log_template_compile(template, template_string, &err), ASSERTION_ERROR("Can't compile template")); \ + assert_string(template->template, template_string, ASSERTION_ERROR("Bad stored template")); + +#define assert_failed_template_compile(template_string) assert_false(log_template_compile(template, template_string, &err), ASSERTION_ERROR("Can compile bad template")); + +#define fill_expected_template_element(element, text, default_value, spec, type, msg_ref) {\ + element.text; \ + element.default_value; \ + element.spec; \ + element.type; \ + element.msg_ref; } + + + +void +test_template_compile_macro() +{ + GError *err = NULL; + LogTemplateElem *element; + LogTemplateElem expected_element; + LogTemplate *template = log_template_new(configuration, NULL); + + assert_template_compile(SIMPLE_STRING); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = SIMPLE_STRING, default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO_ADD_TEXT); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + element = (LogTemplateElem *)template->compiled_template->next->data; + fill_expected_template_element(expected_element, text = "test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO_UNBRACE); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO_UNBRACE_ADD_TEXT); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + element = (LogTemplateElem *)template->compiled_template->next->data; + fill_expected_template_element(expected_element, text = " test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO_MSGREF); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 2); + assert_macro_element(element[0], expected_element); + + assert_template_compile(SIMPLE_MACRO_INVALID_REF); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 1); + assert_macro_element(element[0], expected_element); + element = (LogTemplateElem *)template->compiled_template->next->data; + fill_expected_template_element(expected_element, text = "gmail.com", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(ESCAPED_CHAR); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "Test $STRING", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(VALID_SUBST); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = "default value", macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "$VALUE_NAME", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_2); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "$:VALUE_NAME", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_3); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "${VALUE_NAME}", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_4); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_5); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "$", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_6); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = "", macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + log_template_unref(template); +} + +void +test_template_compile_value() +{ + GError *err = NULL; + LogTemplateElem *element; + LogTemplateElem expected_element; + LogTemplate *template = log_template_new(configuration, NULL); + + assert_template_compile(SIMPLE_VALUE); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE_NAME"), type = LTE_VALUE, msg_ref = 0); + assert_value_element(element[0], expected_element); + + assert_template_compile(SIMPLE_VALUE_UNBRACE); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE_NAME"), type = LTE_VALUE, msg_ref = 0); + assert_value_element(element[0], expected_element); + + assert_template_compile(SIMPLE_VALUE_ESCAPED); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE\\"), type = LTE_VALUE, msg_ref = 0); + assert_value_element(element[0], expected_element); + + assert_template_compile(TRICKY_VALUE_7); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, value_handle = log_msg_get_value_handle(""), type = LTE_VALUE, msg_ref = 0); + assert_value_element(element[0], expected_element); + + log_template_unref(template); +} + +void +test_template_compile_func() +{ + GError *err = NULL; + LogTemplateElem *element; + LogTemplateElem expected_element; + LogTemplate *template = log_template_new(configuration, NULL); + plugin_register(configuration, &hello_plugin, 1); + + assert_template_compile(SIMPLE_TEMPLATE_FUNCTION); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, func.ops = hello_construct(&hello_plugin, configuration, LL_CONTEXT_TEMPLATE_FUNC, "hello"), type = LTE_FUNC, msg_ref = 0); + assert_func_element(element[0], expected_element); + + assert_template_compile(COMPLICATED_TEMPLATE_FUNCTION); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, func.ops = hello_construct(&hello_plugin, configuration, LL_CONTEXT_TEMPLATE_FUNC, "hello"), type = LTE_FUNC, msg_ref = 3); + assert_func_element(element[0], expected_element); + + assert_template_compile(SIMPLE_TEMPLATE_FUNCTION_WITH_ADDITIONAL_TEXT); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "", default_value = NULL, func.ops = hello_construct(&hello_plugin, configuration, LL_CONTEXT_TEMPLATE_FUNC, "hello"), type = LTE_FUNC, msg_ref = 0); + assert_func_element(element[0], expected_element); + element = (LogTemplateElem *)template->compiled_template->next->data; + fill_expected_template_element(expected_element, text = "test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_macro_element(element[0], expected_element); + + log_template_unref(template); +} + +void +test_template_compile_negativ_tests() +{ + GError *err = NULL; + LogTemplateElem *element; + LogTemplateElem expected_element; + LogTemplate *template = log_template_new(configuration, NULL); + + assert_failed_template_compile(INVALID_MACRO); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "error in template: ${MESSAGE", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_bad_element(element[0], expected_element, "Invalid macro, '}' is missing, error_pos='9'"); + g_clear_error(&err); + + + assert_failed_template_compile(INVALID_SUBST); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "error in template: ${MESSAGE:1}", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_bad_element(element[0], expected_element, "Unknown substitution function, error_pos='10'"); + g_clear_error(&err); + + + assert_failed_template_compile(COMPLICATED_TEMPLATE_FUNCTION_BAD_1); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "error in template: $( hello \\tes\t\t\t value(xyz \"value with spaces\" 'test value with spa\"ces')", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_bad_element(element[0], expected_element, "Invalid template function reference, missing function name or inbalanced '(', error_pos='73'"); + g_clear_error(&err); + + assert_failed_template_compile(COMPLICATED_TEMPLATE_FUNCTION_BAD_2); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "error in template: $( hello \\tes\t\t\t value xyz \"value with spaces\" 'test value with spa\"ces'", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_bad_element(element[0], expected_element, "Invalid template function reference, missing function name or inbalanced '(', error_pos='72'"); + g_clear_error(&err); + + assert_failed_template_compile(SIMPLE_UNKNOWN_FUNCTION); + element = (LogTemplateElem *)template->compiled_template->data; + fill_expected_template_element(expected_element, text = "error in template: $(unknown function)", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); + assert_bad_element(element[0], expected_element, "Unknown template function unknown"); + g_clear_error(&err); + + log_template_unref(template); +} + +int main(int argc, char **argv) +{ + msg_init(FALSE); + configuration = cfg_new(0x305); + log_msg_registry_init(); + log_template_global_init(); + + msg_set_post_func(hide_internal_message); + + test_template_compile_macro(); + test_template_compile_value(); + test_template_compile_func(); + test_template_compile_negativ_tests(); + + log_msg_registry_deinit(); + msg_deinit(); + return 0; +} --