diff --git a/lib/filterx/CMakeLists.txt b/lib/filterx/CMakeLists.txt index 40484cb38..d7b03b8d8 100644 --- a/lib/filterx/CMakeLists.txt +++ b/lib/filterx/CMakeLists.txt @@ -61,6 +61,7 @@ set(FILTERX_HEADERS filterx/object-null.h filterx/object-primitive.h filterx/object-string.h + filterx/func-keys.h PARENT_SCOPE ) @@ -127,6 +128,7 @@ set(FILTERX_SOURCES filterx/object-null.c filterx/object-primitive.c filterx/object-string.c + filterx/func-keys.c PARENT_SCOPE ) diff --git a/lib/filterx/Makefile.am b/lib/filterx/Makefile.am index fc876393b..964bb289e 100644 --- a/lib/filterx/Makefile.am +++ b/lib/filterx/Makefile.am @@ -46,6 +46,7 @@ filterxinclude_HEADERS = \ lib/filterx/func-flags.h \ lib/filterx/func-flatten.h \ lib/filterx/func-istype.h \ + lib/filterx/func-keys.h \ lib/filterx/func-len.h \ lib/filterx/func-sdata.h \ lib/filterx/func-set-fields.h \ @@ -111,6 +112,7 @@ filterx_sources = \ lib/filterx/filterx-weakrefs.c \ lib/filterx/func-flatten.c \ lib/filterx/func-istype.c \ + lib/filterx/func-keys.c \ lib/filterx/func-len.c \ lib/filterx/func-sdata.c \ lib/filterx/func-set-fields.c \ diff --git a/lib/filterx/filterx-globals.c b/lib/filterx/filterx-globals.c index 67c977128..e1738b6a8 100644 --- a/lib/filterx/filterx-globals.c +++ b/lib/filterx/filterx-globals.c @@ -47,6 +47,7 @@ #include "filterx/expr-regexp.h" #include "filterx/expr-unset.h" #include "filterx/filterx-eval.h" +#include "filterx/func-keys.h" static GHashTable *filterx_builtin_simple_functions = NULL; static GHashTable *filterx_builtin_function_ctors = NULL; @@ -150,6 +151,7 @@ _ctors_init(void) g_assert(filterx_builtin_function_ctor_register("endswith", filterx_function_endswith_new)); g_assert(filterx_builtin_function_ctor_register("includes", filterx_function_includes_new)); g_assert(filterx_builtin_function_ctor_register("strftime", filterx_function_strftime_new)); + g_assert(filterx_builtin_function_ctor_register("keys", filterx_function_keys_new)); } static void diff --git a/lib/filterx/func-keys.c b/lib/filterx/func-keys.c new file mode 100644 index 000000000..875cc2df0 --- /dev/null +++ b/lib/filterx/func-keys.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2024 Axoflow + * Copyright (c) 2024 shifter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; 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 "filterx/func-keys.h" +#include "filterx/object-dict-interface.h" +#include "filterx/object-list-interface.h" +#include "filterx/object-primitive.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-json.h" + +typedef struct FilterXFunctionKeys_ +{ + FilterXFunction super; + FilterXExpr *object_expr; +} FilterXFunctionKeys; + +static FilterXObject * +_eval(FilterXExpr *s) +{ + FilterXFunctionKeys *self = (FilterXFunctionKeys *) s; + + FilterXObject *object = filterx_expr_eval(self->object_expr); + if (!object) + { + filterx_eval_push_error("Failed to evaluate first argument. " FILTERX_FUNC_KEYS_USAGE, s, NULL); + return NULL; + } + + FilterXObject *result = filterx_json_array_new_empty(); + if (!filterx_dict_keys(object, &result)) + { + filterx_eval_push_error(FILTERX_FUNC_KEYS_ERR_NONDICT FILTERX_FUNC_KEYS_USAGE, s, NULL); + filterx_object_unref(result); + return NULL; + } + return result; +} + +static gboolean +_init(FilterXExpr *s, GlobalConfig *cfg) +{ + FilterXFunctionKeys *self = (FilterXFunctionKeys *) s; + + if (!filterx_expr_init(self->object_expr, cfg)) + return FALSE; + + return filterx_function_init_method(&self->super, cfg); +} + +static void +_deinit(FilterXExpr *s, GlobalConfig *cfg) +{ + FilterXFunctionKeys *self = (FilterXFunctionKeys *) s; + filterx_expr_deinit(self->object_expr, cfg); + filterx_function_deinit_method(&self->super, cfg); +} + +static void +_free(FilterXExpr *s) +{ + FilterXFunctionKeys *self = (FilterXFunctionKeys *) s; + filterx_expr_unref(self->object_expr); + filterx_function_free_method(&self->super); +} + +static FilterXExpr * +_extract_object_expr(FilterXFunctionArgs *args, GError **error) +{ + FilterXExpr *object_expr = filterx_function_args_get_expr(args, 0); + if (!object_expr) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + "argument must be set: object. " FILTERX_FUNC_KEYS_USAGE); + return NULL; + } + + return object_expr; +} + +static gboolean +_extract_args(FilterXFunctionKeys *self, FilterXFunctionArgs *args, GError **error) +{ + if (filterx_function_args_len(args) != 1) + { + g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL, + FILTERX_FUNC_KEYS_ERR_NUM_ARGS FILTERX_FUNC_KEYS_USAGE); + return FALSE; + } + + self->object_expr = _extract_object_expr(args, error); + if (!self->object_expr) + return FALSE; + + return TRUE; +} + +FilterXExpr * +filterx_function_keys_new(FilterXFunctionArgs *args, GError **error) +{ + FilterXFunctionKeys *self = g_new0(FilterXFunctionKeys, 1); + filterx_function_init_instance(&self->super, "keys"); + self->super.super.eval = _eval; + self->super.super.init = _init; + self->super.super.deinit = _deinit; + self->super.super.free_fn = _free; + + if (!_extract_args(self, args, error) || + !filterx_function_args_check(args, error)) + goto error; + + filterx_function_args_free(args); + return &self->super.super; + +error: + filterx_function_args_free(args); + filterx_expr_unref(&self->super.super); + return NULL; +} diff --git a/lib/filterx/func-keys.h b/lib/filterx/func-keys.h new file mode 100644 index 000000000..2d2161c31 --- /dev/null +++ b/lib/filterx/func-keys.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Axoflow + * Copyright (c) 2024 shifter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; 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. + * + */ + +#ifndef FILTERX_FUNC_KEYS_H_INCLUDED +#define FILTERX_FUNC_KEYS_H_INCLUDED + +#include "filterx/expr-function.h" + +#define FILTERX_FUNC_KEYS_USAGE "Usage: keys(dict)" +#define FILTERX_FUNC_KEYS_ERR_NONDICT "Argument must be a dict. " +#define FILTERX_FUNC_KEYS_ERR_NUM_ARGS "Invalid number of arguments. " + +FilterXExpr *filterx_function_keys_new(FilterXFunctionArgs *args, GError **error); + +#endif diff --git a/lib/filterx/object-dict-interface.c b/lib/filterx/object-dict-interface.c index 57a857bb7..e4d2c03dc 100644 --- a/lib/filterx/object-dict-interface.c +++ b/lib/filterx/object-dict-interface.c @@ -27,6 +27,7 @@ #include "filterx/object-json.h" #include "filterx/filterx-object-istype.h" #include "filterx/filterx-ref.h" +#include "filterx/object-list-interface.h" #include "str-utils.h" gboolean @@ -60,6 +61,33 @@ filterx_dict_merge(FilterXObject *s, FilterXObject *other) return filterx_dict_iter(other, _add_elem_to_dict, self); } +static gboolean +_add_elem_to_list(FilterXObject *key_obj, FilterXObject *value_obj, gpointer user_data) +{ + FilterXObject *list = (FilterXObject *) user_data; + + return filterx_list_append(list, &key_obj); +} + +gboolean +filterx_dict_keys(FilterXObject *s, FilterXObject **keys) +{ + g_assert(s); + g_assert(keys); + FilterXObject *obj = filterx_ref_unwrap_ro(s); + if (!filterx_object_is_type(obj, &FILTERX_TYPE_NAME(dict))) + goto error; + g_assert(filterx_object_is_type(*keys, &FILTERX_TYPE_NAME(list))); + + gboolean result = filterx_dict_iter(obj, _add_elem_to_list, *keys); + + filterx_object_unref(s); + return result; +error: + filterx_object_unref(s); + return FALSE; +} + static gboolean _len(FilterXObject *s, guint64 *len) { diff --git a/lib/filterx/object-dict-interface.h b/lib/filterx/object-dict-interface.h index 87dd74d0a..ebd651d9c 100644 --- a/lib/filterx/object-dict-interface.h +++ b/lib/filterx/object-dict-interface.h @@ -45,6 +45,7 @@ struct FilterXDict_ gboolean filterx_dict_iter(FilterXObject *s, FilterXDictIterFunc func, gpointer user_data); gboolean filterx_dict_merge(FilterXObject *s, FilterXObject *other); +gboolean filterx_dict_keys(FilterXObject *s, FilterXObject **keys); void filterx_dict_init_instance(FilterXDict *self, FilterXType *type); diff --git a/lib/filterx/tests/CMakeLists.txt b/lib/filterx/tests/CMakeLists.txt index 71bd70ca2..d067642a0 100644 --- a/lib/filterx/tests/CMakeLists.txt +++ b/lib/filterx/tests/CMakeLists.txt @@ -26,3 +26,5 @@ add_unit_test(LIBTEST CRITERION TARGET test_expr_plus_generator DEPENDS json-plu add_unit_test(LIBTEST CRITERION TARGET test_metrics_labels DEPENDS json-plugin ${JSONC_LIBRARY}) add_unit_test(LIBTEST CRITERION TARGET test_expr_regexp_search DEPENDS json-plugin ${JSONC_LIBRARY}) add_unit_test(LIBTEST CRITERION TARGET test_expr_regexp_subst DEPENDS json-plugin ${JSONC_LIBRARY}) +add_unit_test(LIBTEST CRITERION TARGET test_object_dict_interface DEPENDS json-plugin ${JSONC_LIBRARY}) +add_unit_test(LIBTEST CRITERION TARGET test_func_keys DEPENDS json-plugin ${JSONC_LIBRARY}) diff --git a/lib/filterx/tests/Makefile.am b/lib/filterx/tests/Makefile.am index 67757e996..f7b260865 100644 --- a/lib/filterx/tests/Makefile.am +++ b/lib/filterx/tests/Makefile.am @@ -28,7 +28,9 @@ lib_filterx_tests_TESTS = \ lib/filterx/tests/test_expr_plus \ lib/filterx/tests/test_expr_plus_generator \ lib/filterx/tests/test_expr_plus \ - lib/filterx/tests/test_metrics_labels + lib/filterx/tests/test_metrics_labels \ + lib/filterx/tests/test_object_dict_interface \ + lib/filterx/tests/test_func_keys EXTRA_DIST += lib/filterx/tests/CMakeLists.txt @@ -117,3 +119,9 @@ lib_filterx_tests_test_expr_plus_generator_LDADD = $(TEST_LDADD) $(JSON_LIBS) lib_filterx_tests_test_metrics_labels_CFLAGS = $(TEST_CFLAGS) lib_filterx_tests_test_metrics_labels_LDADD = $(TEST_LDADD) $(JSON_LIBS) + +lib_filterx_tests_test_object_dict_interface_CFLAGS = $(TEST_CFLAGS) +lib_filterx_tests_test_object_dict_interface_LDADD = $(TEST_LDADD) $(JSON_LIBS) + +lib_filterx_tests_test_func_keys_CFLAGS = $(TEST_CFLAGS) +lib_filterx_tests_test_func_keys_LDADD = $(TEST_LDADD) $(JSON_LIBS) diff --git a/lib/filterx/tests/test_func_keys.c b/lib/filterx/tests/test_func_keys.c new file mode 100644 index 000000000..6fd1f717e --- /dev/null +++ b/lib/filterx/tests/test_func_keys.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024 Axoflow + * Copyright (c) 2024 shifter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; 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 +#include "libtest/filterx-lib.h" + +#include "filterx/func-flatten.h" +#include "filterx/object-string.h" +#include "filterx/object-primitive.h" +#include "filterx/object-json.h" +#include "filterx/expr-literal.h" +#include "filterx/func-keys.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-dict-interface.h" +#include "filterx/object-list-interface.h" + +#include "apphook.h" +#include "scratch-buffers.h" + +Test(filterx_func_keys, empty_args) +{ + GList *args = NULL; + + GError *error = NULL; + FilterXExpr *fn = filterx_function_keys_new(filterx_function_args_new(args, NULL), &error); + cr_assert_null(fn); + cr_assert_not_null(error); + + cr_assert_str_eq(error->message, FILTERX_FUNC_KEYS_ERR_NUM_ARGS FILTERX_FUNC_KEYS_USAGE); + g_clear_error(&error); +} + +Test(filterx_func_keys, invalid_args_number) +{ + GList *args = NULL; + args = g_list_append(args, filterx_function_arg_new(NULL, filterx_non_literal_new(filterx_string_new("not a dict", + -1)))); + args = g_list_append(args, filterx_function_arg_new(NULL, filterx_non_literal_new(filterx_string_new("more args", + -1)))); + + GError *error = NULL; + FilterXExpr *fn = filterx_function_keys_new(filterx_function_args_new(args, NULL), &error); + cr_assert_null(fn); + cr_assert_not_null(error); + + cr_assert_str_eq(error->message, FILTERX_FUNC_KEYS_ERR_NUM_ARGS FILTERX_FUNC_KEYS_USAGE); + g_clear_error(&error); +} + +Test(filterx_func_keys, invalid_arg_type) +{ + GList *args = NULL; + args = g_list_append(args, filterx_function_arg_new(NULL, filterx_non_literal_new(filterx_string_new("not a dict", + -1)))); + + GError *error = NULL; + FilterXExpr *fn = filterx_function_keys_new(filterx_function_args_new(args, NULL), &error); + cr_assert_not_null(fn); + cr_assert_null(error); + FilterXObject *res = filterx_expr_eval(fn); + cr_assert_null(res); + + const gchar *last_error = filterx_eval_get_last_error(); + + cr_assert_str_eq(last_error, FILTERX_FUNC_KEYS_ERR_NONDICT FILTERX_FUNC_KEYS_USAGE); + + filterx_expr_unref(fn); + g_clear_error(&error); +} + +Test(filterx_func_keys, valid_input) +{ + GList *args = NULL; + FilterXObject *dict = filterx_json_new_from_repr("{\"foo\":1,\"bar\":[3,2,1],\"baz\":{\"tik\":\"tak\"}}", -1); + args = g_list_append(args, filterx_function_arg_new(NULL, filterx_non_literal_new(dict))); + + GError *error = NULL; + FilterXExpr *fn = filterx_function_keys_new(filterx_function_args_new(args, NULL), &error); + cr_assert_not_null(fn); + cr_assert_null(error); + FilterXObject *res = filterx_expr_eval(fn); + cr_assert_not_null(res); + cr_assert(filterx_object_is_type(res, &FILTERX_TYPE_NAME(list))); + + GString *repr = scratch_buffers_alloc(); + cr_assert(filterx_object_repr(res, repr)); + + cr_assert_str_eq(repr->str, "[\"foo\",\"bar\",\"baz\"]"); + + filterx_object_unref(res); + filterx_expr_unref(fn); + g_clear_error(&error); +} + +static void +setup(void) +{ + app_startup(); + init_libtest_filterx(); +} + +static void +teardown(void) +{ + scratch_buffers_explicit_gc(); + deinit_libtest_filterx(); + app_shutdown(); +} + +TestSuite(filterx_func_keys, .init = setup, .fini = teardown); diff --git a/lib/filterx/tests/test_object_dict_interface.c b/lib/filterx/tests/test_object_dict_interface.c new file mode 100644 index 000000000..78b814ec7 --- /dev/null +++ b/lib/filterx/tests/test_object_dict_interface.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2024 shifter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; 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 +#include "libtest/filterx-lib.h" + +#include "filterx/object-dict-interface.h" +#include "filterx/object-string.h" +#include "filterx/object-json.h" +#include "apphook.h" +#include "scratch-buffers.h" + +Test(filterx_dict_interface, test_keys_empty) +{ + FilterXObject *json = filterx_json_new_from_repr("{}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + gboolean ok = filterx_dict_keys(json, &keys); + cr_assert(ok); + cr_assert_not_null(keys); + + GString *repr = scratch_buffers_alloc(); + cr_assert(filterx_object_repr(keys, repr)); + cr_assert_str_eq(repr->str, "[]"); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_single) +{ + FilterXObject *json = filterx_json_new_from_repr("{\"foo\":\"bar\"}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + gboolean ok = filterx_dict_keys(json, &keys); + cr_assert(ok); + cr_assert_not_null(keys); + + GString *repr = scratch_buffers_alloc(); + cr_assert(filterx_object_repr(keys, repr)); + cr_assert_str_eq("[\"foo\"]", repr->str); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_multi) +{ + FilterXObject *json = filterx_json_new_from_repr("{\"foo\":\"bar\", \"bar\": \"baz\"}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + gboolean ok = filterx_dict_keys(json, &keys); + cr_assert(ok); + cr_assert_not_null(keys); + + GString *repr = scratch_buffers_alloc(); + cr_assert(filterx_object_repr(keys, repr)); + cr_assert_str_eq("[\"foo\",\"bar\"]", repr->str); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_nested) +{ + FilterXObject *json = filterx_json_new_from_repr("{\"foo\":{\"bar\":\"baz\"}, \"bar\":{\"baz\": null}}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + gboolean ok = filterx_dict_keys(json, &keys); + cr_assert(ok); + cr_assert_not_null(keys); + + GString *repr = scratch_buffers_alloc(); + cr_assert(filterx_object_repr(keys, repr)); + cr_assert_str_eq("[\"foo\",\"bar\"]", repr->str); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_null_dict, .signal=SIGABRT) +{ + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + filterx_dict_keys(NULL, &keys); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_null_keys, .signal=SIGABRT) +{ + FilterXObject *json = filterx_json_new_from_repr("{\"foo\":{\"bar\":\"baz\"}, \"bar\":{\"baz\": null}}", -1); + cr_assert_not_null(json); + + filterx_dict_keys(json, NULL); +} + +Test(filterx_dict_interface, test_keys_key_type_is_not_list, .signal=SIGABRT) +{ + FilterXObject *json = filterx_json_new_from_repr("{\"foo\":{\"bar\":\"baz\"}, \"bar\":{\"baz\": null}}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_string_new("this is string", -1); + cr_assert_not_null(keys); + + filterx_dict_keys(json, &keys); + + filterx_object_unref(keys); +} + +Test(filterx_dict_interface, test_keys_object_is_not_dict) +{ + FilterXObject *json = filterx_string_new("{\"foo\":\"bar\", \"bar\": \"baz\"}", -1); + cr_assert_not_null(json); + + FilterXObject *keys = filterx_json_array_new_empty(); + cr_assert_not_null(keys); + + gboolean ok = filterx_dict_keys(json, &keys); + cr_assert(!ok); + guint64 len = G_MAXUINT64; + cr_assert(filterx_object_len(keys, &len)); + cr_assert_eq(0, len); + filterx_object_unref(keys); +} + +static void +setup(void) +{ + app_startup(); + init_libtest_filterx(); +} + +static void +teardown(void) +{ + scratch_buffers_explicit_gc(); + deinit_libtest_filterx(); + app_shutdown(); +} + +TestSuite(filterx_dict_interface, .init = setup, .fini = teardown); diff --git a/tests/light/functional_tests/filterx/test_filterx.py b/tests/light/functional_tests/filterx/test_filterx.py index 6ce1469ce..2fa23ac39 100644 --- a/tests/light/functional_tests/filterx/test_filterx.py +++ b/tests/light/functional_tests/filterx/test_filterx.py @@ -2626,3 +2626,27 @@ def test_set_fields(config, syslog_ng): assert file_true.get_stats()["processed"] == 1 assert "processed" not in file_false.get_stats() assert file_true.read_log() == '{"foo":"foo_override","bar":"bar_exists","baz":"baz_override","almafa":"almafa_default"}\n' + + +def test_keys(config, syslog_ng): + (file_true, file_false) = create_config( + config, r""" + dict = {"foo":{"bar":{"baz":"foobarbaz"}},"tik":{"tak":{"toe":"tiktaktoe"}}}; + $MSG = json(); + $MSG.empty = keys(json()); + $MSG.top_level = keys(dict); + $MSG.nested = keys(dict["foo"]); + $MSG.direct_access = keys(dict)[0]; + """, + ) + syslog_ng.start(config) + + assert file_true.get_stats()["processed"] == 1 + assert "processed" not in file_false.get_stats() + exp = ( + r"""{"empty":[],""" + r""""top_level":["foo","tik"],""" + r""""nested":["bar"],""" + r""""direct_access":"foo"}""" + "\n" + ) + assert file_true.read_log() == exp