Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMiks Kronkalns <miks.kronkalns@zabbix.com>2019-06-17 08:37:48 +0300
committerMiks Kronkalns <miks.kronkalns@zabbix.com>2019-06-17 08:39:09 +0300
commiteec13cafe379634b3213a9bc9982223d9ffa6bc1 (patch)
treec4fc62c5de220745f5abcccbc04d6ac57ab6f967 /tests
parent0375b09191c98206eb90297633ba4b172b909292 (diff)
..F.....S. [ZBXNEXT-5124,ZBX-15827] extended preprocessing steps with final result row; improved input validation in preprocessing steps
* commit 'b0aa9ec70687c15167a5d3c1fd7416a12237017f': (27 commits) .......... [ZBX-15827,ZBXNEXT-5124] fixed changelog .......... [ZBX-15827,ZBXNEXT-5124] fixed changelog .......... [ZBX-15827,ZBXNEXT-5124] fixed changelog ..F....... [ZBXNEXT-5124,ZBX-15827] removed unexplainable click on action link elements once preprocessing results are received ..F....... [ZBXNEXT-5124,ZBX-15827] fixed error displaying in preprocessing steps test dialog when test is performed with invalid previous value ..F....... [ZBX-15827] made 'test all steps' button visible starting from 1 preprocessing step ..F....... [ZBX-15827,ZBXNEXT-5124] fixed coding style ..F....... [ZBX-15827,ZBXNEXT-5124] implemented final result handling in frontend preprocessing test dialog .......PS. [ZBX-15827] fixed crash in case of timeout ...G...PS. [ZBX-15827] fixed "null pointer passed as argument" error ...G...PS. [ZBX-15827] fixed "shadows a previous local" warning ...G...PS. [ZBX-15827] fixed may be used uninitialized warning ...G...PS. [ZBX-15827] fixed indentation ...G...PS. [ZBX-15827] reduced number of variables ...G...PS. [ZBX-15827] removed redundant variable initialization ...G...PS. [ZBX-15827] fixed key parsing not to allow null and boolean .......... [ZBX-15827] fixed memory leaks in cmocka tests ........S. [ZBX-15827] fixed memory leak when parsing incomplete test requests .......PS. [ZBX-15827] refactored json parsing api to return json object type instead of is_null flag ........S. [ZBX-15827] added tests for preprocessing testing ... (cherry picked from commit bff82423f01f1b965b2a564819851f8f151d13f9)
Diffstat (limited to 'tests')
-rw-r--r--tests/zabbix_server/Makefile.am3
-rw-r--r--tests/zabbix_server/preprocessor/Makefile.am2
-rw-r--r--tests/zabbix_server/trapper/Makefile.am49
-rw-r--r--tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.c128
-rw-r--r--tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.yaml1250
-rw-r--r--tests/zbxmockjson.c259
-rw-r--r--tests/zbxmockjson.h29
7 files changed, 1718 insertions, 2 deletions
diff --git a/tests/zabbix_server/Makefile.am b/tests/zabbix_server/Makefile.am
index 48defec4f66..013cdf6f410 100644
--- a/tests/zabbix_server/Makefile.am
+++ b/tests/zabbix_server/Makefile.am
@@ -1,2 +1,3 @@
SUBDIRS = \
- preprocessor
+ preprocessor \
+ trapper
diff --git a/tests/zabbix_server/preprocessor/Makefile.am b/tests/zabbix_server/preprocessor/Makefile.am
index 6b7719e104c..032f2cbd215 100644
--- a/tests/zabbix_server/preprocessor/Makefile.am
+++ b/tests/zabbix_server/preprocessor/Makefile.am
@@ -13,6 +13,7 @@ COMMON_SRC_FILES = \
JSON_LIBS = \
$(top_srcdir)/tests/libzbxmocktest.a \
$(top_srcdir)/tests/libzbxmockdata.a \
+ $(top_srcdir)/src/zabbix_server/preprocessor/libpreprocessor.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
@@ -32,7 +33,6 @@ JSON_LIBS = \
$(top_srcdir)/tests/libzbxmockdata.a
zbx_item_preproc_SOURCES = \
- ../../../src/zabbix_server/preprocessor/item_preproc.c \
zbx_item_preproc.c
zbx_item_preproc_LDADD = $(JSON_LIBS)
diff --git a/tests/zabbix_server/trapper/Makefile.am b/tests/zabbix_server/trapper/Makefile.am
new file mode 100644
index 00000000000..22650e761d4
--- /dev/null
+++ b/tests/zabbix_server/trapper/Makefile.am
@@ -0,0 +1,49 @@
+if SERVER
+SERVER_tests = zbx_trapper_preproc_test_run
+
+noinst_PROGRAMS = $(SERVER_tests)
+
+COMMON_SRC_FILES = \
+ ../../zbxmocktest.h
+
+TRAPPER_LIBS = \
+ $(top_srcdir)/tests/libzbxmocktest.a \
+ $(top_srcdir)/tests/libzbxmockdata.a \
+ $(top_srcdir)/src/zabbix_server/preprocessor/libpreprocessor.a \
+ $(top_srcdir)/src/libs/zbxipcservice/libzbxipcservice.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
+ $(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
+ $(top_srcdir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
+ $(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
+ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
+ $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
+ $(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
+ $(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
+ $(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
+ $(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
+ $(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
+ $(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxembed/libzbxembed.a \
+ $(top_srcdir)/src/libs/zbxprometheus/libzbxprometheus.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_srcdir)/tests/libzbxmockdata.a
+
+zbx_trapper_preproc_test_run_SOURCES = \
+ zbx_trapper_preproc_test_run.c \
+ ../../../src/zabbix_server/trapper/trapper_preproc.c \
+ ../../zbxmockjson.c
+
+zbx_trapper_preproc_test_run_LDADD = $(TRAPPER_LIBS)
+zbx_trapper_preproc_test_run_LDADD += @SERVER_LIBS@
+zbx_trapper_preproc_test_run_LDFLAGS = @SERVER_LDFLAGS@
+
+zbx_trapper_preproc_test_run_CFLAGS = \
+ -I@top_srcdir@/tests @LIBXML2_CFLAGS@ \
+ -Wl,--wrap=zbx_preprocessor_test \
+ -Wl,--wrap=DBget_user_by_active_session
+
+endif
+
diff --git a/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.c b/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.c
new file mode 100644
index 00000000000..822f55b9cdf
--- /dev/null
+++ b/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.c
@@ -0,0 +1,128 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "zbxmocktest.h"
+#include "zbxmockdata.h"
+#include "zbxmockassert.h"
+#include "zbxmockutil.h"
+#include "zbxmockjson.h"
+
+#include "common.h"
+#include "zbxjson.h"
+#include "dbcache.h"
+#include "zbxembed.h"
+#include "log.h"
+#include "preproc.h"
+#include "../../../src/zabbix_server/preprocessor/item_preproc.h"
+#include "../../../src/zabbix_server/preprocessor/preproc_history.h"
+
+zbx_es_t es_engine;
+
+int zbx_trapper_preproc_test_run(const struct zbx_json_parse *jp, struct zbx_json *json, char **error);
+
+int __wrap_zbx_preprocessor_test(unsigned char value_type, const char *value, const zbx_timespec_t *ts,
+ const zbx_vector_ptr_t *steps, zbx_vector_ptr_t *results, zbx_vector_ptr_t *history,
+ char **preproc_error, char **error)
+{
+ int i, results_num;
+ zbx_preproc_op_t *steps_array;
+ zbx_preproc_result_t *results_array, *result;
+ zbx_vector_ptr_t history_out;
+ zbx_variant_t value_var;
+
+ ZBX_UNUSED(error);
+
+ zbx_vector_ptr_create(&history_out);
+ zbx_variant_set_str(&value_var, zbx_strdup(NULL, value));
+
+ steps_array = (zbx_preproc_op_t *)zbx_malloc(NULL, steps->values_num * sizeof(zbx_preproc_op_t));
+ for (i = 0; i < steps->values_num; i++)
+ steps_array[i] = *(zbx_preproc_op_t *)steps->values[i];
+
+ results_array = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t) * steps->values_num);
+ memset(results_array, 0, sizeof(zbx_preproc_result_t) * steps->values_num);
+
+ zbx_item_preproc_test(value_type, &value_var, ts, steps_array, steps->values_num, history, &history_out,
+ results_array, &results_num, preproc_error);
+
+ /* copy output history */
+ zbx_vector_ptr_clear_ext(history, (zbx_clean_func_t)zbx_preproc_op_history_free);
+
+ if (0 != history_out.values_num)
+ zbx_vector_ptr_append_array(history, history_out.values, history_out.values_num);
+
+ /* copy results */
+ for (i = 0; i < results_num; i++)
+ {
+ result = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t));
+ *result = results_array[i];
+ zbx_vector_ptr_append(results, result);
+ }
+
+ zbx_variant_clear(&value_var);
+ zbx_free(steps_array);
+ zbx_free(results_array);
+ zbx_vector_ptr_destroy(&history_out);
+
+ return SUCCEED;
+}
+
+int __wrap_DBget_user_by_active_session(const char *sessionid, zbx_user_t *user)
+{
+ ZBX_UNUSED(sessionid);
+
+ user->type = USER_TYPE_ZABBIX_ADMIN;
+ user->userid = 0;
+
+ return SUCCEED;
+}
+
+void zbx_mock_test_entry(void **state)
+{
+ const char *request;
+ char *error = NULL;
+ struct zbx_json_parse jp;
+ struct zbx_json out;
+ int returned_ret, expected_ret;
+
+ ZBX_UNUSED(state);
+
+ zbx_json_init(&out, 1024);
+
+ request = zbx_mock_get_parameter_string("in.request");
+ if (FAIL == zbx_json_open(request, &jp))
+ fail_msg("Invalid request format: %s", zbx_json_strerror());
+
+ returned_ret = zbx_trapper_preproc_test_run(&jp, &out, &error);
+ if (FAIL == returned_ret)
+ printf("zbx_trapper_preproc_test_run error: %s\n", error);
+ else
+ printf("zbx_trapper_preproc_test_run output: %s\n", out.buffer);
+
+ expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+ zbx_mock_assert_result_eq("Return value", expected_ret, returned_ret);
+
+ if (FAIL == returned_ret)
+ zbx_mock_assert_ptr_ne("Error pointer", NULL, error);
+ else
+ zbx_mock_assert_json_eq("Output", zbx_mock_get_parameter_string("out.response"), out.buffer);
+
+ zbx_free(error);
+ zbx_json_free(&out);
+}
diff --git a/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.yaml b/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.yaml
new file mode 100644
index 00000000000..b8403833e92
--- /dev/null
+++ b/tests/zabbix_server/trapper/zbx_trapper_preproc_test_run.yaml
@@ -0,0 +1,1250 @@
+---
+test case: Empty request
+in:
+ request: |
+ {
+ }
+out:
+ return: FAIL
+---
+test case: Missing sessionid field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data field
+in:
+ request: |
+ {
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.steps field
+in:
+ request: |
+ {
+ "data": {
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.value_type field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.value field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.steps[0].error_handler_params field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.steps[0].params field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.steps[0].error_handler field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.steps[0].type field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0
+ }
+ ],
+ "value_type": 0,
+ "value": "1"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.history.timestamp field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1",
+ "history": {
+ "value": "0"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: Missing data.history.value field
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "1",
+ "history": {
+ "timestamp": "now-1m"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: FAIL
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to data: 4$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: 4"
+ },
+ {
+ "result": "4"
+ },
+ {
+ "result": "8"
+ }
+ ],
+ "result": "8"
+ }
+ }
+---
+test case: 'Apply mult(2) + trim($) + regsub("data: *(.*)", \1) to data: 4$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ },
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + mult(2) + regsub("data: *(.*)", \1) to data: 4$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: 4"
+ },
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to data: x$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "data: x$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: x"
+ },
+ {
+ "result": "x"
+ },
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to 4$ with discard on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 1,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "4"
+ },
+ {
+ "result": null,
+ "action": 1,
+ "error": "/.*"
+ }
+ ],
+ "result": null
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to 4$ with set value to 5 on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "5",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 2,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "4"
+ },
+ {
+ "result": "5",
+ "action": 2,
+ "error": "/.*"
+ },
+ {
+ "result": "10"
+ }
+ ],
+ "result": "10"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to 4$ with set error to Validation error on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "Validation error",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 3,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "4$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "4"
+ },
+ {
+ "failed": "Validation error",
+ "action": 3,
+ "error": "/[^V][^a][^l][^i][^d].*"
+ }
+ ],
+ "error": "Validation error"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) to data: x$ for uint value'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 3,
+ "value": "data: x$"
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: x"
+ },
+ {
+ "result": "x"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply regsub("data: *(.*)", \1) to data: x for uint value testing single step'
+in:
+ request: |
+ {
+ "data": {
+ "steps":[
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 3,
+ "value": "data: x",
+ "single": true
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "x"
+ }
+ ],
+ "result": "x"
+ }
+ }
+---
+test case: 'Apply delta() to 100, 700'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "",
+ "error_handler": 0,
+ "type": 9
+ }
+ ],
+ "value_type": 0,
+ "value": "700",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "100"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "600"
+ }
+ ],
+ "result": "600"
+ }
+ }
+---
+test case: 'Apply delta_per_second() to 100, 700'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "",
+ "error_handler": 0,
+ "type": 10
+ }
+ ],
+ "value_type": 0,
+ "value": "700",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "100"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "10"
+ }
+ ],
+ "result": "10"
+ }
+ }
+---
+test case: 'Apply mult(2) + trim($) + regsub("data: *(.*)", \1) to history data: 4$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ },
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: 4$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "previous": true,
+ "steps": [
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + mult(2) + regsub("data: *(.*)", \1) to history data: 4$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4$",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: 4$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "previous": true,
+ "steps": [
+ {
+ "result": "data: 4"
+ },
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to history data: x$'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 4$",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: x$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "previous": true,
+ "steps": [
+ {
+ "result": "data: x"
+ },
+ {
+ "result": "x"
+ },
+ {
+ "error": "/.*"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to history 4$ with discard on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 1,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 3",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "4$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: 3"
+ },
+ {
+ "result": "3"
+ },
+ {
+ "result": "6"
+ }
+ ],
+ "result": "6"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to history 4$ with set value to 5 on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "5",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 2,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 3",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "4$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "data: 3"
+ },
+ {
+ "result": "3"
+ },
+ {
+ "result": "6"
+ }
+ ],
+ "result": "6"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) + mult(2) to history 4$ with set error to Validation error on fail'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "Validation error",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 3,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "2",
+ "error_handler": 0,
+ "type": 1
+ }
+ ],
+ "value_type": 0,
+ "value": "4$",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "4$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "previous": true,
+ "steps": [
+ {
+ "result": "4"
+ },
+ {
+ "failed": "Validation error",
+ "action": 3,
+ "error": "/[^V][^a][^l][^i][^d].*"
+ }
+ ],
+ "error": "Validation error"
+ }
+ }
+---
+test case: 'Apply trim($) + regsub("data: *(.*)", \1) to history data: x$ for uint value'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "",
+ "params": "$",
+ "error_handler": 0,
+ "type": 4
+ },
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 3,
+ "value": "data: 1$",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: x$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "previous": true,
+ "steps": [
+ {
+ "result": "data: x"
+ },
+ {
+ "result": "x"
+ }
+ ],
+ "error": "/.*"
+ }
+ }
+---
+test case: 'Apply regsub("data: *(.*)", \1) to history data: x for uint value testing single step'
+in:
+ request: |
+ {
+ "data": {
+ "steps":[
+ {
+ "error_handler_params": "",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 0,
+ "type": 5
+ }
+ ],
+ "value_type": 3,
+ "value": "data: x",
+ "single": true,
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: x$"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "x"
+ }
+ ],
+ "result": "x"
+ }
+ }
+---
+test case: 'Apply regsub("data: *(.*)", \1) + delta() to data: 9, data:10'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "0",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 2,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "",
+ "error_handler": 0,
+ "type": 9
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 10",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "data: 9"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "10"
+ },
+ {
+ "result": "1"
+ }
+ ],
+ "result": "1"
+ }
+ }
+---
+test case: 'Apply regsub("data: *(.*)", \1) + delta() to data: 9, data:10'
+in:
+ request: |
+ {
+ "data": {
+ "steps": [
+ {
+ "error_handler_params": "0",
+ "params": "data: *(.*)\n\\1",
+ "error_handler": 2,
+ "type": 5
+ },
+ {
+ "error_handler_params": "",
+ "params": "",
+ "error_handler": 0,
+ "type": 9
+ }
+ ],
+ "value_type": 0,
+ "value": "data: 10",
+ "history": {
+ "timestamp": "now-1m",
+ "value": "x"
+ }
+ },
+ "request": "preprocessing.test",
+ "sid": "6ed71f17963a881bd010e63b01c39484"
+ }
+out:
+ return: SUCCEED
+ response: |
+ {
+ "response": "success",
+ "data": {
+ "steps": [
+ {
+ "result": "10"
+ },
+ {
+ "result": "10"
+ }
+ ],
+ "result": "10"
+ }
+ }
+...
diff --git a/tests/zbxmockjson.c b/tests/zbxmockjson.c
new file mode 100644
index 00000000000..fda1e0f0ccf
--- /dev/null
+++ b/tests/zbxmockjson.c
@@ -0,0 +1,259 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "zbxalgo.h"
+#include "zbxjson.h"
+#include "zbxregexp.h"
+
+#include "zbxmocktest.h"
+#include "zbxmockdata.h"
+#include "zbxmockassert.h"
+
+#define _FAIL(file, line, prefix, message, ...) \
+ \
+do \
+{ \
+ cm_print_error("%s%s" message "\n", (NULL != prefix_msg ? prefix_msg : ""), \
+ (NULL != prefix_msg && '\0' != *prefix_msg ? ": " : ""), \
+ __VA_ARGS__); \
+ _fail(file, line); \
+} \
+while(0)
+
+void cm_print_error(const char * const format, ...);
+
+static void json_flatten_contents(struct zbx_json_parse *jp, const char *prefix, zbx_vector_ptr_pair_t *props);
+
+static void json_append_prop(zbx_vector_ptr_pair_t *props, const char *key, const char *value)
+{
+ zbx_ptr_pair_t pair;
+
+ pair.first = zbx_strdup(NULL, key);
+ pair.second = zbx_strdup(NULL, value);
+ zbx_vector_ptr_pair_append_ptr(props, &pair);
+}
+
+static int json_compare_props(const void *d1, const void *d2)
+{
+ const zbx_ptr_pair_t *p1 = (const zbx_ptr_pair_t *)d1;
+ const zbx_ptr_pair_t *p2 = (const zbx_ptr_pair_t *)d2;
+
+ return strcmp((const char *)p1->first, (const char *)p2->first);
+}
+
+static void json_flatten_value(const char *ptr, const char *path, zbx_vector_ptr_pair_t *props)
+{
+ struct zbx_json_parse jp_value;
+ char *value = NULL;
+ size_t value_alloc = 0;
+ zbx_json_type_t type;
+
+ if (FAIL == zbx_json_brackets_open(ptr, &jp_value))
+ {
+ zbx_json_decodevalue_dyn(ptr, &value, &value_alloc, &type);
+ json_append_prop(props, path, (ZBX_JSON_TYPE_NULL != type ? value : "null"));
+ }
+ else
+ json_flatten_contents(&jp_value, path, props);
+
+ zbx_free(value);
+}
+
+static int json_quote_key(char *key, size_t size)
+{
+ char *ptr, *out;
+ int quotes = 0, dot = 1;
+
+ for (ptr = key; '\0' != *ptr; ptr++)
+ {
+ if ('\'' == *ptr || '\\' == *ptr)
+ quotes++;
+
+ if (0 == isalnum((unsigned char)*ptr) && '_' != *ptr && '-' != *ptr)
+ dot = 0;
+ }
+
+ if (1 == dot)
+ return FAIL;
+
+ if (0 == quotes)
+ return SUCCEED;
+
+ if (ptr - key + quotes + 1 > (int)size)
+ fail_msg("The hardcoded 2k limit exceeded by JSON key: %s", key);
+
+ for (out = ptr + quotes; ptr != key; ptr--)
+ {
+ *out-- = *ptr;
+ if ('\'' == *ptr || '\\' == *ptr)
+ *out-- = '\\';
+ }
+
+ return SUCCEED;
+}
+
+static void json_flatten_object(struct zbx_json_parse *jp, const char *prefix, zbx_vector_ptr_pair_t *props)
+{
+ const char *pnext = NULL;
+ char *path = NULL, key[MAX_STRING_LEN];
+ size_t path_alloc = 0, path_offset = 0;
+
+ while (NULL != (pnext = zbx_json_pair_next(jp, pnext, key, sizeof(key))))
+ {
+ path_offset = 0;
+ if (SUCCEED == json_quote_key(key, sizeof(key)))
+ zbx_snprintf_alloc(&path, &path_alloc, &path_offset, "%s['%s']", prefix, key);
+ else
+ zbx_snprintf_alloc(&path, &path_alloc, &path_offset, "%s.%s", prefix, key);
+
+ json_flatten_value(pnext, path, props);
+ }
+ zbx_free(path);
+}
+
+static void json_flatten_array(struct zbx_json_parse *jp, const char *parent, zbx_vector_ptr_pair_t *props)
+{
+ const char *pnext;
+ char *path, *value = NULL;
+ int index = 0;
+
+
+ for (pnext = NULL; NULL != (pnext = zbx_json_next(jp, pnext));)
+ {
+ path = zbx_dsprintf(NULL, "%s[%d]", parent, index++);
+ json_flatten_value(pnext, path, props);
+ zbx_free(path);
+ }
+
+ zbx_free(value);
+}
+
+static void json_flatten_contents(struct zbx_json_parse *jp, const char *prefix, zbx_vector_ptr_pair_t *props)
+{
+ if ('{' == *jp->start)
+ json_flatten_object(jp, prefix, props);
+ else if ('[' == *jp->start)
+ json_flatten_array(jp, prefix, props);
+}
+
+/******************************************************************************
+ * *
+ * Function: json_flatten *
+ * *
+ * Purpose: flattens json into vector of key (json path), value pairs, sorted *
+ * by keys *
+ * *
+ ******************************************************************************/
+static void json_flatten(struct zbx_json_parse *jp, zbx_vector_ptr_pair_t *props)
+{
+ json_flatten_contents(jp, "$", props);
+ zbx_vector_ptr_pair_sort(props, json_compare_props);
+}
+
+/******************************************************************************
+ * *
+ * Function: __zbx_mock_assert_json_eq *
+ * *
+ * Purpose: compares returned json with expected *
+ * *
+ * Comments: The comparison is done by first flattening both jsons into *
+ * key(jsonpath)-value pairs, sorting by keys and then comparing *
+ * the resulting lists. *
+ * If expected value starts with / then regular expression match is *
+ * performed. *
+ * *
+ ******************************************************************************/
+void __zbx_mock_assert_json_eq(const char *file, int line, const char *prefix_msg, const char *expected_value,
+ const char *returned_value)
+{
+ struct zbx_json_parse jp_expected, jp_returned;
+ zbx_vector_ptr_pair_t props_expected, props_returned;
+ int i, props_num;
+
+ if (FAIL == zbx_json_open(expected_value, &jp_expected))
+ _FAIL(file, line, prefix_msg, "Expected value is not a valid JSON object: %s", zbx_json_strerror());
+
+ if (FAIL == zbx_json_open(returned_value, &jp_returned))
+ _FAIL(file, line, prefix_msg, "Returned value is not a valid JSON object: %s", zbx_json_strerror());
+
+ zbx_vector_ptr_pair_create(&props_expected);
+ zbx_vector_ptr_pair_create(&props_returned);
+
+ json_flatten(&jp_expected, &props_expected);
+ json_flatten(&jp_returned, &props_returned);
+
+ props_num = MIN(props_expected.values_num, props_returned.values_num);
+
+ for (i = 0; i < props_num; i++)
+ {
+ zbx_ptr_pair_t *pair_expected = &props_expected.values[i];
+ zbx_ptr_pair_t *pair_returned = &props_returned.values[i];
+
+ if (0 != strcmp(pair_expected->first, pair_returned->first))
+ {
+ _FAIL(file, line, prefix_msg, "Expected key \"%s\" while got \"%s\"", pair_expected->first,
+ pair_returned->first);
+ }
+
+ if ('/' == *(char *)pair_expected->second)
+ {
+ char *pattern = (char *)pair_expected->second + 1;
+ if (NULL == zbx_regexp_match(pair_returned->second, pattern, NULL))
+ {
+ _FAIL(file, line, prefix_msg, "Key \"%s\" value \"%s\" does not match pattern \"%s\"",
+ pair_returned->first, pair_returned->second, pattern);
+ }
+ }
+ else
+ {
+ if (0 != strcmp(pair_expected->second, pair_returned->second))
+ {
+ _FAIL(file, line, prefix_msg, "Expected key \"%s\" value \"%s\" while got \"%s\"",
+ pair_expected->first, pair_expected->second, pair_returned->second);
+
+ }
+ }
+ }
+
+ if (i < props_expected.values_num)
+ {
+ zbx_ptr_pair_t *pair_expected = &props_expected.values[i];
+ _FAIL(file, line, prefix_msg, "Expected key \"%s\" while got nothing", pair_expected->first);
+ }
+
+ if (i < props_returned.values_num)
+ {
+ zbx_ptr_pair_t *pair_returned = &props_returned.values[i];
+ _FAIL(file, line, prefix_msg, "Did not expect key \"%s\"", pair_returned->first);
+ }
+
+ for (i = 0; i < props_expected.values_num; i++)
+ {
+ zbx_free(props_expected.values[i].first);
+ zbx_free(props_expected.values[i].second);
+ }
+ zbx_vector_ptr_pair_destroy(&props_expected);
+
+ for (i = 0; i < props_returned.values_num; i++)
+ {
+ zbx_free(props_returned.values[i].first);
+ zbx_free(props_returned.values[i].second);
+ }
+ zbx_vector_ptr_pair_destroy(&props_returned);
+}
diff --git a/tests/zbxmockjson.h b/tests/zbxmockjson.h
new file mode 100644
index 00000000000..9e4d4045fb8
--- /dev/null
+++ b/tests/zbxmockjson.h
@@ -0,0 +1,29 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#ifndef ZABBIX_MOCK_JSON_H
+#define ZABBIX_MOCK_JSON_H
+
+void __zbx_mock_assert_json_eq(const char *file, int line, const char *prefix_msg, const char *expected_value,
+ const char *returned_value);
+
+#define zbx_mock_assert_json_eq(prefix_msg, expected_value, returned_value) \
+ __zbx_mock_assert_json_eq(__FILE__, __LINE__, prefix_msg, expected_value, returned_value)
+
+#endif /* BUILD_TESTS_ZBXMOCKDB_H_ */