Skip to content

Commit

Permalink
xml: add filterx parse_xml() tests
Browse files Browse the repository at this point in the history
Signed-off-by: Attila Szakacs <[email protected]>
  • Loading branch information
alltilla committed Aug 13, 2024
1 parent 46ba55a commit 2de6425
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 1 deletion.
1 change: 1 addition & 0 deletions modules/xml/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_unit_test(CRITERION TARGET test_xml_parser DEPENDS xml syslog-ng)
add_unit_test(CRITERION TARGET test_windows_eventlog_xml_parser DEPENDS xml syslog-ng)
add_unit_test(LIBTEST CRITERION TARGET test_filterx_parse_xml DEPENDS xml syslog-ng)
10 changes: 9 additions & 1 deletion modules/xml/tests/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
modules_xml_tests_TESTS = \
modules/xml/tests/test_xml_parser \
modules/xml/tests/test_windows_eventlog_xml_parser
modules/xml/tests/test_windows_eventlog_xml_parser \
modules/xml/tests/test_filterx_parse_xml

check_PROGRAMS += ${modules_xml_tests_TESTS}

Expand All @@ -18,4 +19,11 @@ modules_xml_tests_test_windows_eventlog_xml_parser_LDFLAGS = \
-dlpreopen $(top_builddir)/modules/xml/libxml.la
EXTRA_modules_xml_tests_test_windows_eventlog_xml_parser_DEPENDENCIES = $(top_builddir)/modules/xml/libxml.la

modules_xml_tests_test_filterx_parse_xml_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/xml
modules_xml_tests_test_filterx_parse_xml_LDADD = $(TEST_LDADD)
modules_xml_tests_test_filterx_parse_xml_LDFLAGS = \
$(PREOPEN_SYSLOGFORMAT) \
-dlpreopen $(top_builddir)/modules/xml/libxml.la
EXTRA_modules_xml_tests_test_filterx_parse_xml_DEPENDENCIES = $(top_builddir)/modules/xml/libxml.la

EXTRA_DIST += modules/xml/tests/CMakeLists.txt
174 changes: 174 additions & 0 deletions modules/xml/tests/test_filterx_parse_xml.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2024 Axoflow
* Copyright (c) 2024 Attila Szakacs <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As an additional exemption you are allowed to compile & link against the
* OpenSSL libraries as published by the OpenSSL project. See the file
* COPYING for details.
*/


#include <criterion/criterion.h>

#include "filterx-parse-xml.h"
#include "filterx/object-string.h"
#include "filterx/object-json.h"
#include "filterx/filterx-eval.h"
#include "scratch-buffers.h"
#include "apphook.h"
#include "cfg.h"

#include "libtest/filterx-lib.h"

static FilterXExpr *
_create_parse_xml_expr(const gchar *raw_xml, FilterXObject *fillable)
{
FilterXFunctionArg *input = filterx_function_arg_new(NULL, filterx_non_literal_new(filterx_string_new(raw_xml, -1)));
GList *args_list = g_list_append(NULL, input);
GError *error = NULL;
FilterXFunctionArgs *args = filterx_function_args_new(args_list, &error);
g_assert(!error);

FilterXExpr *func = filterx_generator_function_parse_xml_new("test", args, &error);
g_assert(!error);

FilterXExpr *fillable_expr = filterx_non_literal_new(fillable);
filterx_generator_set_fillable(func, fillable_expr);

g_error_free(error);
return func;
}

static void
_assert_parse_xml_fail(const gchar *raw_xml)
{
FilterXExpr *func = _create_parse_xml_expr(raw_xml, filterx_json_object_new_empty());

FilterXObject *result = filterx_expr_eval(func);
cr_assert(!result);
cr_assert(filterx_eval_get_last_error());

filterx_eval_clear_errors();
filterx_expr_unref(func);
}

static void
_assert_parse_xml_with_fillable(const gchar *raw_xml, const gchar *expected_json, FilterXObject *fillable)
{
FilterXExpr *func = _create_parse_xml_expr(raw_xml, fillable);

FilterXObject *result = filterx_expr_eval(func);
cr_assert(result);
cr_assert(!filterx_eval_get_last_error());

cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(json_object)));

GString *formatted_result = g_string_new(NULL);
filterx_object_repr(result, formatted_result);
cr_assert_str_eq(formatted_result->str, expected_json);

g_string_free(formatted_result, TRUE);
filterx_object_unref(result);
filterx_expr_unref(func);
}

static void
_assert_parse_xml(const gchar *raw_xml, const gchar *expected_json)
{
_assert_parse_xml_with_fillable(raw_xml, expected_json, filterx_json_object_new_empty());
}

Test(filterx_parse_xml, invalid_inputs)
{
_assert_parse_xml_fail("");
_assert_parse_xml_fail("simple string");
_assert_parse_xml_fail("<tag></missingtag>");
_assert_parse_xml_fail("<tag></tag></extraclosetag>");
_assert_parse_xml_fail("<tag><tag></tag>");
_assert_parse_xml_fail("<tag1><tag2>closewrongorder</tag1></tag2>");
_assert_parse_xml_fail("<tag id=\"missingquote></tag>");
_assert_parse_xml_fail("<tag id='missingquote></tag>");
_assert_parse_xml_fail("<tag id=missingquote\"></tag>");
_assert_parse_xml_fail("<tag id=missingquote'></tag>");
_assert_parse_xml_fail("<space in tag/>");
_assert_parse_xml_fail("</>");
_assert_parse_xml_fail("<tag></tag>>");
}

Test(filterx_parse_xml, valid_inputs)
{
_assert_parse_xml("<a></a>",
"{\"a\":\"\"}");
_assert_parse_xml("<a><b></b></a>",
"{\"a\":{\"b\":\"\"}}");
_assert_parse_xml("<a><b>foo</b></a>",
"{\"a\":{\"b\":\"foo\"}}");
_assert_parse_xml("<a><b>foo</b><c>bar</c></a>",
"{\"a\":{\"b\":\"foo\",\"c\":\"bar\"}}");
_assert_parse_xml("<a attr=\"attr_val\">foo</a>",
"{\"a\":{\"@attr\":\"attr_val\",\"#text\":\"foo\"}}");
_assert_parse_xml("<a attr=\"attr_val\"></a>",
"{\"a\":{\"@attr\":\"attr_val\"}}");
_assert_parse_xml("<a><b>c</b><b>d</b></a>",
"{\"a\":{\"b\":[\"c\",\"d\"]}}");
_assert_parse_xml("<a><b>c</b><b>d</b><b>e</b></a>",
"{\"a\":{\"b\":[\"c\",\"d\",\"e\"]}}");
_assert_parse_xml("<a><b attr=\"attr_val\">c</b><b>e</b></a>",
"{\"a\":{\"b\":[{\"@attr\":\"attr_val\",\"#text\":\"c\"},\"e\"]}}");
_assert_parse_xml("<a><b>c</b><b attr=\"attr_val\">e</b></a>",
"{\"a\":{\"b\":[\"c\",{\"@attr\":\"attr_val\",\"#text\":\"e\"}]}}");
_assert_parse_xml("<a><b>c</b><b>d</b><b><e>f</e></b></a>",
"{\"a\":{\"b\":[\"c\",\"d\",{\"e\":\"f\"}]}}");
_assert_parse_xml("<a><b><c>d</c></b><b><e>f</e></b></a>",
"{\"a\":{\"b\":[{\"c\":\"d\"},{\"e\":\"f\"}]}}");
_assert_parse_xml("<a><b><c>d</c></b><e>f</e><b><g>h</g></b></a>",
"{\"a\":{\"b\":[{\"c\":\"d\"},{\"g\":\"h\"}],\"e\":\"f\"}}");
_assert_parse_xml("<a>b<c>d</c></a>",
"{\"a\":{\"#text\":\"b\",\"c\":\"d\"}}");
/*
* This is not a valid XML, as a valid XML must have exactly one root element,
* but supporting this could be useful for parsing sub-XMLs, also dropping these
* XMLs would take additional processing/validating.
*/
_assert_parse_xml("<a>b</a><a>c</a>",
"{\"a\":[\"b\",\"c\"]}");

}

Test(filterx_parse_xml, overwrite_existing_invalid_value)
{
FilterXObject *fillable = filterx_json_object_new_from_repr("{\"a\":42}", -1);
_assert_parse_xml_with_fillable("<a><b>foo</b></a>", "{\"a\":{\"b\":\"foo\"}}", fillable);
}

static void
setup(void)
{
configuration = cfg_new_snippet();
app_startup();
init_libtest_filterx();
}

static void
teardown(void)
{
scratch_buffers_explicit_gc();
deinit_libtest_filterx();
app_shutdown();
cfg_free(configuration);
}

TestSuite(filterx_parse_xml, .init = setup, .fini = teardown);
1 change: 1 addition & 0 deletions tests/copyright/policy
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ modules/correlation/group-lines.h
modules/xml/windows-eventlog-xml-parser\.h
modules/xml/filterx-parse-xml\.[ch]$
modules/xml/tests/test_windows_eventlog_xml_parser\.c
modules/xml/tests/test_filterx_parse_xml\.c
modules/examples/filterx/example-filterx-func/example-filterx-func-plugin\.[ch]
modules/grpc/otel/filterx
modules/kvformat/filterx-func-parse-kv\.[ch]
Expand Down
14 changes: 14 additions & 0 deletions tests/light/functional_tests/filterx/test_filterx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1948,3 +1948,17 @@ def test_plus_equal_grammar_rules(config, syslog_ng):
r""""attr_gen_var":["some","basic","foo","bar","and","add","to","plus"]}""" + "\n"
)
assert file_true.read_log() == exp


def test_parse_xml(config, syslog_ng):
(file_true, file_false) = create_config(
config, r"""
custom_message = "<a><b attr=\"attr_val\">c</b><b>e</b></a>";
$MSG = json(parse_xml(custom_message));
""",
)
syslog_ng.start(config)

assert file_true.get_stats()["processed"] == 1
assert "processed" not in file_false.get_stats()
assert file_true.read_log() == "{\"a\":{\"b\":[{\"@attr\":\"attr_val\",\"#text\":\"c\"},\"e\"]}}\n"

0 comments on commit 2de6425

Please sign in to comment.