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
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
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)
-rw-r--r--.gitignore5
-rw-r--r--ChangeLog1
-rw-r--r--conf_tests.m41
-rw-r--r--frontends/php/app/controllers/CControllerPopupPreprocTestEdit.php4
-rw-r--r--frontends/php/app/controllers/CControllerPopupPreprocTestSend.php46
-rw-r--r--frontends/php/app/views/popup.preproctestedit.view.js.php74
-rw-r--r--frontends/php/app/views/popup.preproctestedit.view.php9
-rw-r--r--frontends/php/include/forms.inc.php2
-rw-r--r--frontends/php/include/views/js/item.preprocessing.js.php18
-rw-r--r--include/common.h2
-rw-r--r--include/preproc.h5
-rw-r--r--include/zbxjson.h16
-rw-r--r--src/libs/zbxcommon/misc.c57
-rw-r--r--src/libs/zbxdbcache/dbcache.c65
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c73
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.h5
-rw-r--r--src/zabbix_server/preprocessor/preproc_worker.c76
-rw-r--r--src/zabbix_server/preprocessor/preprocessing.c74
-rw-r--r--src/zabbix_server/trapper/trapper_preproc.c300
-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
26 files changed, 2233 insertions, 320 deletions
diff --git a/.gitignore b/.gitignore
index 2a9ea39461b..090ec11cd35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -152,7 +152,12 @@ tests/libs/zbxsysinfo/parse_item_key
tests/libs/zbxsysinfo/process
tests/libs/zbxcommon/zbx_user_macro_parse
tests/libs/zbxdbcache/is_item_processed_by_server
+<<<<<<< HEAD
+=======
+tests/libs/zbxjson/zbx_jsonpath_next
+>>>>>>> ........S. [ZBX-15827] added tests for preprocessing testing
tests/zabbix_server/preprocessor/item_preproc_xpath
tests/zabbix_server/preprocessor/zbx_item_preproc
+tests/zabbix_server/trapper/zbx_trapper_preproc_test_run
/zabbix-*.tar.gz
.vscode
diff --git a/ChangeLog b/ChangeLog
index 4faaea61bbd..617a2bb5b1e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,7 @@ Bug fixes:
Changes for 4.2.4rc1
New features:
+..F.....S. [ZBXNEXT-5124,ZBX-15827] extended preprocessing steps with final result row; improved input validation in preprocessing steps (miks, wiper)
.......PS. [ZBXNEXT-2880] added access to vmware datastore at vmware vCenter level (MVekslers)
..F....... [ZBXNEXT-5163] added display of maintenance information in Configuration section for hosts in maitenance (vasilijs)
..F....... [ZBXNEXT-5036] added preloader for popup menus (ashubin)
diff --git a/conf_tests.m4 b/conf_tests.m4
index 8b1f6067a8d..9351563e589 100644
--- a/conf_tests.m4
+++ b/conf_tests.m4
@@ -37,6 +37,7 @@ AC_DEFUN([CONF_TESTS],[
tests/zabbix_server/Makefile
tests/zabbix_server/preprocessor/Makefile
tests/libs/zbxcomms/Makefile
+ tests/zabbix_server/trapper/Makefile
])
AC_DEFINE([HAVE_TESTS], [1], ["Define to 1 if tests directory is present"])
])
diff --git a/frontends/php/app/controllers/CControllerPopupPreprocTestEdit.php b/frontends/php/app/controllers/CControllerPopupPreprocTestEdit.php
index 0dd5ab89dc4..4e9c26f7b87 100644
--- a/frontends/php/app/controllers/CControllerPopupPreprocTestEdit.php
+++ b/frontends/php/app/controllers/CControllerPopupPreprocTestEdit.php
@@ -32,7 +32,8 @@ class CControllerPopupPreprocTestEdit extends CControllerPopupPreprocTest {
'steps' => 'required|array',
'delay' => 'string',
'data' => 'array',
- 'step_obj' => 'required|int32'
+ 'step_obj' => 'required|int32',
+ 'show_final_result' => 'in 0,1'
];
$ret = $this->validateInput($fields);
@@ -118,6 +119,7 @@ class CControllerPopupPreprocTestEdit extends CControllerPopupPreprocTest {
'value_type' => $this->getInput('value_type'),
'test_type' => $this->getInput('test_type'),
'step_obj' => $this->getInput('step_obj'),
+ 'show_final_result' => $this->getInput('show_final_result'),
'user' => [
'debug_mode' => $this->getDebugMode()
]
diff --git a/frontends/php/app/controllers/CControllerPopupPreprocTestSend.php b/frontends/php/app/controllers/CControllerPopupPreprocTestSend.php
index f2e3c2106dd..2d1e66e0c83 100644
--- a/frontends/php/app/controllers/CControllerPopupPreprocTestSend.php
+++ b/frontends/php/app/controllers/CControllerPopupPreprocTestSend.php
@@ -27,6 +27,11 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
/**
* @var bool
*/
+ protected $show_final_result;
+
+ /**
+ * @var bool
+ */
protected $use_prev_value;
/**
@@ -46,7 +51,8 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
'macros' => 'array',
'value' => 'string',
'prev_value' => 'string',
- 'prev_time' => 'string'
+ 'prev_time' => 'string',
+ 'show_final_result' => 'in 0,1'
];
$ret = $this->validateInput($fields);
@@ -56,6 +62,7 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
$prepr_types = zbx_objectValues($steps, 'type');
$this->preproc_item = self::getPreprocessingItemType($this->getInput('test_type'));
$this->use_prev_value = (count(array_intersect($prepr_types, self::$preproc_steps_using_prev_value)) > 0);
+ $this->show_final_result = ($this->getInput('show_final_result') == 1);
// Check preprocessing steps.
if (($error = $this->preproc_item->validateItemPreprocessingSteps($steps)) !== true) {
@@ -123,7 +130,8 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
$data = [
'value' => $this->getInput('value', ''),
'value_type' => $this->getInput('value_type', ITEM_VALUE_TYPE_STR),
- 'steps' => $this->getInput('steps')
+ 'steps' => $this->getInput('steps'),
+ 'single' => !$this->show_final_result
];
// Resolve macros used in parameter fields.
@@ -178,14 +186,15 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
}
elseif (is_array($result)) {
$test_failed = false;
+ $test_outcome = null;
foreach ($data['steps'] as $i => &$step) {
if ($test_failed) {
// If test is failed, proceesing steps are skipped from results.
unset($data['steps'][$i]);
continue;
}
- elseif (array_key_exists($i, $result)) {
- $step += $result[$i];
+ elseif (array_key_exists($i, $result['steps'])) {
+ $step += $result['steps'][$i];
if (array_key_exists('error', $step)) {
// If error happened and no value is set, frontend shows label 'No value'.
@@ -200,9 +209,38 @@ class CControllerPopupPreprocTestSend extends CControllerPopupPreprocTest {
unset($step['params']);
unset($step['error_handler']);
unset($step['error_handler_params']);
+
+ // Latest executed step due to the error or end of preprocessing.
+ $test_outcome = $step + ['action' => ZBX_PREPROC_FAIL_DEFAULT];
}
unset($step);
+ if (array_key_exists('previous', $result) && $result['previous'] === true) {
+ error(_s('Incorrect value for "%1$s" field.', _('Previous value')));
+ }
+ elseif ($this->show_final_result) {
+ if (array_key_exists('result', $result)) {
+ $output['final'] = [
+ 'action' => _s('Result converted to %1$s', itemValueTypeString($data['value_type'])),
+ 'result' => $result['result']
+ ];
+ }
+ elseif (array_key_exists('error', $result)) {
+ $output['final'] = [
+ 'action' => ($test_outcome['action'] == ZBX_PREPROC_FAIL_SET_ERROR)
+ ? _('Set error to')
+ : '',
+ 'error' => $result['error']
+ ];
+ }
+
+ if ($output['final']['action'] !== '') {
+ $output['final']['action'] = (new CSpan($output['final']['action']))
+ ->addClass(ZBX_STYLE_GREY)
+ ->toString();
+ }
+ }
+
$output['steps'] = $data['steps'];
}
diff --git a/frontends/php/app/views/popup.preproctestedit.view.js.php b/frontends/php/app/views/popup.preproctestedit.view.js.php
index 3d60dd2c551..72655153e4e 100644
--- a/frontends/php/app/views/popup.preproctestedit.view.js.php
+++ b/frontends/php/app/views/popup.preproctestedit.view.js.php
@@ -22,6 +22,35 @@
ob_start(); ?>
/**
+ * Make step result UI element.
+ *
+ * @param array step Step object returned from server.
+ *
+ * @return jQuery
+ */
+function makeStepResult(step) {
+ if (typeof step.error !== 'undefined') {
+ return jQuery(new Template(jQuery('#preprocessing-step-error-icon').html()).evaluate(
+ {error: step.error || <?= CJs::encodeJson(_('<empty string>')) ?>}
+ ));
+ }
+ else if (typeof step.result === 'undefined' || step.result === null) {
+ return jQuery('<span>', {'class': '<?= ZBX_STYLE_GREY ?>'}).text(<?= CJs::encodeJson(_('No value')) ?>);
+ }
+ else if (step.result === '') {
+ return jQuery('<span>', {'class': '<?= ZBX_STYLE_GREY ?>'}).text(<?= CJs::encodeJson(_('<empty string>')) ?>);
+ }
+ else if (step.result.indexOf("\n") != -1 || step.result.length > 25) {
+ return jQuery(new Template(jQuery('#preprocessing-step-result').html()).evaluate(
+ jQuery.extend({result: step.result})
+ ));
+ }
+ else {
+ return jQuery('<span>').text(step.result);
+ }
+}
+
+/**
* Send item preprocessing test details and display results in table.
*
* @param string formid Selector for form to send.
@@ -55,6 +84,10 @@ function itemPreprocessingTest(form) {
// Clean previous results.
jQuery('[id^="preproc-test-step-"][id$="-result"]').empty();
jQuery('[id^="preproc-test-step-"][id$="-name"] > div').remove();
+ jQuery('#final-result')
+ .hide()
+ .find('.table-forms-td-right')
+ .empty();
},
success: function(ret) {
jQuery(form).parent().find('.msg-bad, .msg-good').remove();
@@ -63,7 +96,19 @@ function itemPreprocessingTest(form) {
if (typeof ret.messages !== 'undefined') {
jQuery(ret.messages).insertBefore(jQuery(form));
- jQuery(form).parent().find('.link-action').click();
+ }
+
+ if (typeof ret.final !== 'undefined') {
+ var result = makeStepResult(ret.final);
+ if (result !== null) {
+ $result = jQuery(result).css('float', 'right');
+ }
+
+ jQuery('#final-result')
+ .show()
+ .find('.table-forms-td-right')
+ .append(ret.final.action)
+ .append($result);
}
jQuery('#value, #time, [name^=macros]').prop('disabled', false);
@@ -87,10 +132,8 @@ function itemPreprocessingTest(form) {
* @param array steps Array of objects containing details about each preprocessing step test results.
*/
function processItemPreprocessingTestResults(steps) {
- var tmpl_err_icon = new Template(jQuery('#preprocessing-step-error-icon').html()),
- tmpl_gray_label = new Template(jQuery('#preprocessing-gray-label').html()),
- tmpl_act_done = new Template(jQuery('#preprocessing-step-action-done').html()),
- tmpl_step_result = new Template(jQuery('#preprocessing-step-result').html());
+ var tmpl_gray_label = new Template(jQuery('#preprocessing-gray-label').html()),
+ tmpl_act_done = new Template(jQuery('#preprocessing-step-action-done').html());
steps.each(function(step, i) {
if (typeof step.action !== 'undefined') {
@@ -119,24 +162,7 @@ function processItemPreprocessingTestResults(steps) {
}
}
- if (typeof step.error !== 'undefined') {
- step.result = jQuery(
- tmpl_err_icon.evaluate({error: step.error || <?= CJs::encodeJson(_('<empty string>')) ?>})
- );
- }
- else if (typeof step.result === 'undefined' || step.result === null) {
- step.result = jQuery('<span>',
- {'class': '<?= ZBX_STYLE_GREY ?>'}
- ).text(<?= CJs::encodeJson(_('No value')) ?>);
- }
- else if (step.result === '') {
- step.result = jQuery('<span>',
- {'class': '<?= ZBX_STYLE_GREY ?>'}
- ).text(<?= CJs::encodeJson(_('<empty string>')) ?>);
- }
- else if (step.result.indexOf("\n") != -1 || step.result.length > 25) {
- step.result = jQuery(tmpl_step_result.evaluate(jQuery.extend({result: step.result})));
- }
+ step.result = makeStepResult(step);
if (typeof step.action !== 'undefined' && step.action !== null) {
jQuery('#preproc-test-step-'+i+'-name').append(jQuery(tmpl_gray_label.evaluate(<?= CJs::encodeJson([
@@ -177,6 +203,8 @@ function savePreprocessingTestInputs() {
}
jQuery(document).ready(function($) {
+ $('#final-result').hide();
+
$('#value').multilineInput({
placeholder: <?= CJs::encodeJson(_('value')) ?>,
value: <?= CJs::encodeJson($data['value']) ?>,
diff --git a/frontends/php/app/views/popup.preproctestedit.view.php b/frontends/php/app/views/popup.preproctestedit.view.php
index f761bb7ca50..22984b6e10f 100644
--- a/frontends/php/app/views/popup.preproctestedit.view.php
+++ b/frontends/php/app/views/popup.preproctestedit.view.php
@@ -25,6 +25,7 @@ $form = (new CForm())
->addVar('hostid', $data['hostid'])
->addVar('value_type', $data['value_type'])
->addVar('test_type', $data['test_type'])
+ ->addVar('show_final_result', $data['show_final_result'])
->setId('preprocessing-test-form');
// Create macros table.
@@ -117,6 +118,14 @@ $form_list->addRow(
->addStyle('width: 100%;')
);
+if ($data['show_final_result']) {
+ $form_list->addRow(
+ _('Result'),
+ new CDiv(),
+ 'final-result'
+ );
+}
+
$form
->addItem($form_list)
->addItem((new CInput('submit', 'submit'))->addStyle('display: none;'));
diff --git a/frontends/php/include/forms.inc.php b/frontends/php/include/forms.inc.php
index 011e262e7ad..2e48cc01850 100644
--- a/frontends/php/include/forms.inc.php
+++ b/frontends/php/include/forms.inc.php
@@ -1627,7 +1627,7 @@ function getItemPreprocessing(CForm $form, array $preprocessing, $readonly, arra
(new CDiv(
(new CButton('preproc_test_all', _('Test all steps')))
->addClass(ZBX_STYLE_BTN_LINK)
- ->addStyle(($i > 1) ? null : 'display: none')
+ ->addStyle(($i > 0) ? null : 'display: none')
))->addClass('step-action')
]))->addClass('preprocessing-list-foot')
);
diff --git a/frontends/php/include/views/js/item.preprocessing.js.php b/frontends/php/include/views/js/item.preprocessing.js.php
index 936b5eb8d6f..00a66beb940 100644
--- a/frontends/php/include/views/js/item.preprocessing.js.php
+++ b/frontends/php/include/views/js/item.preprocessing.js.php
@@ -112,10 +112,11 @@
/**
* Creates preprocessing test modal window.
*
- * @param {array} step_nums List of step numbers to collect.
- * @param {object} trigger_elmnt UI element triggered function.
+ * @param {array} step_nums List of step numbers to collect.
+ * @param {bool} show_final_result Either the final result should be displayed.
+ * @param {object} trigger_elmnt UI element triggered function.
*/
- function openPreprocessingTestDialog(step_nums, trigger_elmnt) {
+ function openPreprocessingTestDialog(step_nums, show_final_result, trigger_elmnt) {
var $step_obj = $(trigger_elmnt).closest('.preprocessing-list-item, .preprocessing-list-foot');
PopUp('popup.preproctest.edit', $.extend({
@@ -124,7 +125,8 @@
steps: getPreprocessingSteps(step_nums),
hostid: <?= $data['hostid'] ?>,
test_type: <?= $data['preprocessing_test_type'] ?>,
- step_obj: $step_obj.attr('data-step') || -1
+ step_obj: $step_obj.attr('data-step') || -1,
+ show_final_result: show_final_result ? 1 : 0
}, {'data': $step_obj.data('test-data') || []}), 'preprocessing-test', trigger_elmnt);
}
@@ -252,12 +254,12 @@
var sortable_count = $preprocessing.find('li.sortable').length;
if (sortable_count == 1) {
+ $('#preproc_test_all').show();
$preprocessing
.sortable('disable')
.find('div.<?= ZBX_STYLE_DRAG_ICON ?>').addClass('<?= ZBX_STYLE_DISABLED ?>');
}
else if (sortable_count > 1) {
- $('#preproc_test_all').show();
$preprocessing
.sortable('enable')
.find('div.<?= ZBX_STYLE_DRAG_ICON ?>').removeClass('<?= ZBX_STYLE_DISABLED ?>');
@@ -272,13 +274,13 @@
step_nums.push(str.substr(14, str.length - 21));
});
- openPreprocessingTestDialog(step_nums, this);
+ openPreprocessingTestDialog(step_nums, true, this);
})
.on('click', '.preprocessing-step-test', function() {
var str = $(this).attr('name'),
num = str.substr(14, str.length - 21);
- openPreprocessingTestDialog([num], this);
+ openPreprocessingTestDialog([num], false, this);
})
.on('click', '.element-table-remove', function() {
$(this).closest('li.sortable').remove();
@@ -286,10 +288,10 @@
var sortable_count = $preprocessing.find('li.sortable').length;
if (sortable_count == 0) {
+ $('#preproc_test_all').hide();
$('.preprocessing-list-head').hide();
}
else if (sortable_count == 1) {
- $('#preproc_test_all').hide();
$preprocessing
.sortable('disable')
.find('div.<?= ZBX_STYLE_DRAG_ICON ?>').addClass('<?= ZBX_STYLE_DISABLED ?>');
diff --git a/include/common.h b/include/common.h
index 7cab4448323..2ee7a94ddcc 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1547,4 +1547,6 @@ char *zbx_create_token(zbx_uint64_t seed);
#define ZBX_PROBLEM_SUPPRESSED_FALSE 0
#define ZBX_PROBLEM_SUPPRESSED_TRUE 1
+int zbx_variant_to_value_type(zbx_variant_t *value, unsigned char value_type, char **errmsg);
+
#endif
diff --git a/include/preproc.h b/include/preproc.h
index e43536a5f24..450822ae4bc 100644
--- a/include/preproc.h
+++ b/include/preproc.h
@@ -43,7 +43,8 @@ zbx_uint64_t zbx_preprocessor_get_queue_size(void);
void zbx_preproc_op_free(zbx_preproc_op_t *op);
void zbx_preproc_result_free(zbx_preproc_result_t *result);
-int zbx_preprocessor_test(unsigned char value_type, const char *value, const char *last_value, const char *last_ts,
- const zbx_vector_ptr_t *steps, zbx_vector_ptr_t *results, char **preproc_error, char **error);
+int 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);
#endif /* ZABBIX_PREPROC_H */
diff --git a/include/zbxjson.h b/include/zbxjson.h
index 8e450d19c23..7b37f98b5ae 100644
--- a/include/zbxjson.h
+++ b/include/zbxjson.h
@@ -109,13 +109,15 @@
#define ZBX_PROTO_TAG_ACTION "action"
#define ZBX_PROTO_TAG_FAILED "failed"
#define ZBX_PROTO_TAG_RESULT "result"
-#define ZBX_PROTO_TAG_LINE_RAW "line_raw"
-#define ZBX_PROTO_TAG_LABELS "labels"
-#define ZBX_PROTO_TAG_HELP "help"
-#define ZBX_PROTO_TAG_MEDIATYPEID "mediatypeid"
-#define ZBX_PROTO_TAG_SENDTO "sendto"
-#define ZBX_PROTO_TAG_SUBJECT "subject"
-#define ZBX_PROTO_TAG_MESSAGE "message"
+#define ZBX_PROTO_TAG_LINE_RAW "line_raw"
+#define ZBX_PROTO_TAG_LABELS "labels"
+#define ZBX_PROTO_TAG_HELP "help"
+#define ZBX_PROTO_TAG_MEDIATYPEID "mediatypeid"
+#define ZBX_PROTO_TAG_SENDTO "sendto"
+#define ZBX_PROTO_TAG_SUBJECT "subject"
+#define ZBX_PROTO_TAG_MESSAGE "message"
+#define ZBX_PROTO_TAG_PREVIOUS "previous"
+#define ZBX_PROTO_TAG_SINGLE "single"
#define ZBX_PROTO_VALUE_FAILED "failed"
#define ZBX_PROTO_VALUE_SUCCESS "success"
diff --git a/src/libs/zbxcommon/misc.c b/src/libs/zbxcommon/misc.c
index 0f7a15830aa..c2974bd057b 100644
--- a/src/libs/zbxcommon/misc.c
+++ b/src/libs/zbxcommon/misc.c
@@ -3735,3 +3735,60 @@ void zbx_update_env(double time_now)
#endif
}
}
+
+/******************************************************************************
+ * *
+ * Function: zbx_variant_to_value_type *
+ * *
+ * Purpose: converts variant value to type compatible with requested value *
+ * type *
+ * *
+ * Parameters: value - [IN/OUT] the value to convert *
+ * value_type - [IN] the target value type *
+ * errmsg - [OUT] the error message *
+ * *
+ * Return value: SUCCEED - Value conversion was successful. *
+ * FAIL - Otherwise *
+ * *
+ ******************************************************************************/
+int zbx_variant_to_value_type(zbx_variant_t *value, unsigned char value_type, char **errmsg)
+{
+ int ret;
+
+ zbx_free(*errmsg);
+
+ switch (value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT:
+ if (SUCCEED == (ret = zbx_variant_convert(value, ZBX_VARIANT_DBL)))
+ {
+ if (FAIL == (ret = zbx_validate_value_dbl(value->data.dbl)))
+ {
+ *errmsg = zbx_dsprintf(NULL, "Value " ZBX_FS_DBL " is too small or too large.",
+ value->data.dbl);
+ }
+ }
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ ret = zbx_variant_convert(value, ZBX_VARIANT_UI64);
+ break;
+ case ITEM_VALUE_TYPE_STR:
+ case ITEM_VALUE_TYPE_TEXT:
+ case ITEM_VALUE_TYPE_LOG:
+ ret = zbx_variant_convert(value, ZBX_VARIANT_STR);
+ break;
+ default:
+ *errmsg = zbx_dsprintf(NULL, "Unknown value type \"%d\"", value_type);
+ THIS_SHOULD_NEVER_HAPPEN;
+ ret = FAIL;
+ }
+
+ if (FAIL == ret && NULL == *errmsg)
+ {
+ *errmsg = zbx_dsprintf(NULL, "Value \"%s\" of type \"%s\" is not suitable for value type \"%s\"",
+ zbx_variant_value_desc(value), zbx_variant_type_desc(value),
+ zbx_item_value_type_string(value_type));
+ }
+
+ return ret;
+}
diff --git a/src/libs/zbxdbcache/dbcache.c b/src/libs/zbxdbcache/dbcache.c
index 6e3c36e6dbe..5109179c6a5 100644
--- a/src/libs/zbxdbcache/dbcache.c
+++ b/src/libs/zbxdbcache/dbcache.c
@@ -1727,51 +1727,15 @@ static void dc_history_set_error(ZBX_DC_HISTORY *hdata, char *errmsg)
* value_type - [IN] the item value type *
* value - [IN] the value to set *
* *
- * Return value: SUCCEED - Value conversion was successful. *
- * FAIL - Otherwise *
- * *
******************************************************************************/
-static int dc_history_set_value(ZBX_DC_HISTORY *hdata, unsigned char value_type, zbx_variant_t *value)
+static void dc_history_set_value(ZBX_DC_HISTORY *hdata, unsigned char value_type, zbx_variant_t *value)
{
- int ret;
char *errmsg = NULL;
- switch (value_type)
- {
- case ITEM_VALUE_TYPE_FLOAT:
- if (SUCCEED == (ret = zbx_variant_convert(value, ZBX_VARIANT_DBL)))
- {
- if (FAIL == (ret = zbx_validate_value_dbl(value->data.dbl)))
- {
- errmsg = zbx_dsprintf(NULL, "Value " ZBX_FS_DBL " is too small or too large.",
- value->data.dbl);
- }
- }
- break;
- case ITEM_VALUE_TYPE_UINT64:
- ret = zbx_variant_convert(value, ZBX_VARIANT_UI64);
- break;
- case ITEM_VALUE_TYPE_STR:
- case ITEM_VALUE_TYPE_TEXT:
- case ITEM_VALUE_TYPE_LOG:
- ret = zbx_variant_convert(value, ZBX_VARIANT_STR);
- break;
- default:
- THIS_SHOULD_NEVER_HAPPEN;
- return FAIL;
- }
-
- if (FAIL == ret)
+ if (FAIL == zbx_variant_to_value_type(value, value_type, &errmsg))
{
- if (NULL == errmsg)
- {
- errmsg = zbx_dsprintf(NULL, "Value \"%s\" of type \"%s\" is not suitable for"
- " value type \"%s\"", zbx_variant_value_desc(value),
- zbx_variant_type_desc(value), zbx_item_value_type_string(value_type));
- }
-
dc_history_set_error(hdata, errmsg);
- return FAIL;
+ return;
}
switch (value_type)
@@ -1807,8 +1771,6 @@ static int dc_history_set_value(ZBX_DC_HISTORY *hdata, unsigned char value_type,
hdata->value_type = value_type;
zbx_variant_set_none(value);
-
- return ret;
}
/******************************************************************************
@@ -1821,25 +1783,17 @@ static int dc_history_set_value(ZBX_DC_HISTORY *hdata, unsigned char value_type,
* Parameters: item - [IN] the item *
* hdata - [IN/OUT] the historical data to process *
* *
- * Return value: SUCCEED - Normalization was successful. *
- * FAIL - Otherwise - ZBX_DC_FLAG_UNDEF will be set and item *
- * state changed to ZBX_NOTSUPPORTED. *
- * *
******************************************************************************/
-static int normalize_item_value(const DC_ITEM *item, ZBX_DC_HISTORY *hdata)
+static void normalize_item_value(const DC_ITEM *item, ZBX_DC_HISTORY *hdata)
{
- int ret = FAIL;
char *logvalue;
zbx_variant_t value_var;
if (0 != (hdata->flags & ZBX_DC_FLAG_NOVALUE))
- {
- ret = SUCCEED;
- goto out;
- }
+ return;
if (ITEM_STATE_NOTSUPPORTED == hdata->state)
- goto out;
+ return;
if (0 == (hdata->flags & ZBX_DC_FLAG_NOHISTORY))
hdata->ttl = item->history_sec;
@@ -1864,11 +1818,10 @@ static int normalize_item_value(const DC_ITEM *item, ZBX_DC_HISTORY *hdata)
{
dc_history_set_error(hdata, zbx_dsprintf(NULL, "Value " ZBX_FS_DBL
" is too small or too large.", hdata->value.dbl));
- return FAIL;
}
break;
}
- return SUCCEED;
+ return;
}
switch (hdata->value_type)
@@ -1890,10 +1843,8 @@ static int normalize_item_value(const DC_ITEM *item, ZBX_DC_HISTORY *hdata)
break;
}
- ret = dc_history_set_value(hdata, item->value_type, &value_var);
+ dc_history_set_value(hdata, item->value_type, &value_var);
zbx_variant_clear(&value_var);
-out:
- return ret;
}
/******************************************************************************
diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c
index 0a5ceb92268..bae5fd0db44 100644
--- a/src/zabbix_server/preprocessor/item_preproc.c
+++ b/src/zabbix_server/preprocessor/item_preproc.c
@@ -31,6 +31,7 @@
#include "zbxjson.h"
#include "zbxembed.h"
#include "zbxprometheus.h"
+#include "preproc_history.h"
#include "item_preproc.h"
@@ -1875,6 +1876,78 @@ int zbx_item_preproc_handle_error(zbx_variant_t *value, const zbx_preproc_op_t *
return FAIL;
}
}
+
+/******************************************************************************
+ * *
+ * Function: zbx_item_preproc_test *
+ * *
+ * Purpose: test preprocessing steps *
+ * *
+ * Parameters: value_type - [IN] the item value type *
+ * value - [IN/OUT] the value to process *
+ * ts - [IN] the value timestamp *
+ * steps - [IN] the preprocessing steps to execute *
+ * steps_num - [IN] the number of preprocessing steps *
+ * history_in - [IN] the preprocessing history *
+ * history_out - [OUT] the new preprocessing history *
+ * results - [OUT] the preprocessing step results *
+ * results_num - [OUT] the number of step results *
+ * error - [OUT] error message *
+ * *
+ * Return value: SUCCEED - the preprocessing steps finished successfully *
+ * FAIL - otherwise, error contains the error message *
+ * *
+ ******************************************************************************/
+int zbx_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
+ zbx_preproc_op_t *steps, int steps_num, zbx_vector_ptr_t *history_in, zbx_vector_ptr_t *history_out,
+ zbx_preproc_result_t *results, int *results_num, char **error)
+{
+ int i, ret = SUCCEED;
+
+ for (i = 0; i < steps_num; i++)
+ {
+ zbx_preproc_op_t *op = &steps[i];
+ zbx_variant_t history_value;
+ zbx_timespec_t history_ts;
+
+ zbx_preproc_history_pop_value(history_in, i, &history_value, &history_ts);
+
+ if (FAIL == (ret = zbx_item_preproc(value_type, value, ts, op, &history_value, &history_ts, error)))
+ {
+ results[i].action = op->error_handler;
+ results[i].error = zbx_strdup(NULL, *error);
+ ret = zbx_item_preproc_handle_error(value, op, error);
+ }
+ else
+ {
+ results[i].action = ZBX_PREPROC_FAIL_DEFAULT;
+ results[i].error = NULL;
+ }
+
+ if (SUCCEED != ret)
+ {
+ zbx_variant_set_none(&results[i].value);
+ zbx_variant_clear(&history_value);
+ break;
+ }
+
+ zbx_variant_set_variant(&results[i].value, value);
+
+ if (ZBX_VARIANT_NONE != history_value.type)
+ {
+ /* the value is byte copied to history_out vector and doesn't have to be cleared */
+ zbx_preproc_history_add_value(history_out, i, &history_value, &history_ts);
+ }
+
+ if (ZBX_VARIANT_NONE == value->type)
+ break;
+ }
+
+ *results_num = (i == steps_num ? i : i + 1);
+
+ return ret;
+}
+
#ifdef HAVE_TESTS
# include "../../../tests/zabbix_server/preprocessor/item_preproc_test.c"
#endif
diff --git a/src/zabbix_server/preprocessor/item_preproc.h b/src/zabbix_server/preprocessor/item_preproc.h
index b1252aa1a31..27199ed8505 100644
--- a/src/zabbix_server/preprocessor/item_preproc.h
+++ b/src/zabbix_server/preprocessor/item_preproc.h
@@ -21,6 +21,7 @@
#define ZABBIX_ITEM_PREPROC_H
#include "dbcache.h"
+#include "preproc.h"
int zbx_item_preproc(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
const zbx_preproc_op_t *op, zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **error);
@@ -30,4 +31,8 @@ int zbx_item_preproc_handle_error(zbx_variant_t *value, const zbx_preproc_op_t *
int zbx_item_preproc_convert_value_to_numeric(zbx_variant_t *value_num, const zbx_variant_t *value,
unsigned char value_type, char **errmsg);
+int zbx_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
+ zbx_preproc_op_t *steps, int steps_num, zbx_vector_ptr_t *history_in, zbx_vector_ptr_t *history_out,
+ zbx_preproc_result_t *results, int *results_num, char **error);
+
#endif
diff --git a/src/zabbix_server/preprocessor/preproc_worker.c b/src/zabbix_server/preprocessor/preproc_worker.c
index bf9397d0b71..64ef91e0234 100644
--- a/src/zabbix_server/preprocessor/preproc_worker.c
+++ b/src/zabbix_server/preprocessor/preproc_worker.c
@@ -358,80 +358,6 @@ static void worker_preprocess_value(zbx_ipc_socket_t *socket, zbx_ipc_message_t
/******************************************************************************
* *
- * Function: worker_item_preproc_test *
- * *
- * Purpose: test preprocessing steps *
- * *
- * Parameters: value_type - [IN] the item value type *
- * value - [IN/OUT] the value to process *
- * ts - [IN] the value timestamp *
- * steps - [IN] the preprocessing steps to execute *
- * steps_num - [IN] the number of preprocessing steps *
- * history_in - [IN] the preprocessing history *
- * history_out - [OUT] the new preprocessing history *
- * results - [OUT] the preprocessing step results *
- * results_num - [OUT] the number of step results *
- * error - [OUT] error message *
- * *
- * Return value: SUCCEED - the preprocessing steps finished successfully *
- * FAIL - otherwise, error contains the error message *
- * *
- ******************************************************************************/
-static int worker_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
- zbx_preproc_op_t *steps, int steps_num, zbx_vector_ptr_t *history_in, zbx_vector_ptr_t *history_out,
- zbx_preproc_result_t *results, int *results_num, char **error)
-{
- int i, ret = SUCCEED;
-
- for (i = 0; i < steps_num; i++)
- {
- zbx_preproc_op_t *op = &steps[i];
- zbx_variant_t history_value;
- zbx_timespec_t history_ts;
-
- zbx_preproc_history_pop_value(history_in, i, &history_value, &history_ts);
-
- if (FAIL == (ret = zbx_item_preproc(value_type, value, ts, op, &history_value, &history_ts, error)))
- {
- results[i].action = op->error_handler;
- ret = zbx_item_preproc_handle_error(value, op, error);
- }
- else
- results[i].action = ZBX_PREPROC_FAIL_DEFAULT;
-
- if (NULL != *error)
- {
- results[i].error = zbx_strdup(NULL, *error);
- ret = FAIL;
- }
-
- if (SUCCEED != ret)
- {
- zbx_variant_set_none(&results[i].value);
- zbx_variant_clear(&history_value);
- break;
- }
-
- zbx_variant_set_variant(&results[i].value, value);
- results[i].error = NULL;
-
- if (ZBX_VARIANT_NONE != history_value.type)
- {
- /* the value is byte copied to history_out vector and doesn't have to be cleared */
- zbx_preproc_history_add_value(history_out, i, &history_value, &history_ts);
- }
-
- if (ZBX_VARIANT_NONE == value->type)
- break;
- }
-
- *results_num = (i == steps_num ? i : i + 1);
-
- return ret;
-}
-
-/******************************************************************************
- * *
* Function: worker_test_value *
* *
* Purpose: handle item value test preprocessing task *
@@ -464,7 +390,7 @@ static void worker_test_value(zbx_ipc_socket_t *socket, zbx_ipc_message_t *messa
results = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t) * steps_num);
memset(results, 0, sizeof(zbx_preproc_result_t) * steps_num);
- worker_item_preproc_test(value_type, &value, &ts, steps, steps_num, &history_in, &history_out, results,
+ zbx_item_preproc_test(value_type, &value, &ts, steps, steps_num, &history_in, &history_out, results,
&results_num, &error);
size = zbx_preprocessor_pack_test_result(&data, results, results_num, &history_out, error);
diff --git a/src/zabbix_server/preprocessor/preprocessing.c b/src/zabbix_server/preprocessor/preprocessing.c
index baf62573da1..c815c3b2baa 100644
--- a/src/zabbix_server/preprocessor/preprocessing.c
+++ b/src/zabbix_server/preprocessor/preprocessing.c
@@ -998,76 +998,30 @@ void zbx_preprocessor_unpack_test_request(unsigned char *value_type, char **valu
* Purpose: tests item preprocessing with the specified input value and steps *
* *
******************************************************************************/
-int zbx_preprocessor_test(unsigned char value_type, const char *value, const char *last_value, const char *last_ts,
- const zbx_vector_ptr_t *steps, zbx_vector_ptr_t *results, char **preproc_error, char **error)
+int 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)
{
- unsigned char *data = NULL;
- zbx_uint32_t size;
- zbx_timespec_t ts, timestamps[2];
- int ret = FAIL, i, values_num = 0;
- zbx_vector_ptr_t history;
- const char *values[2];
+ unsigned char *data = NULL;
+ zbx_uint32_t size;
+ int ret = FAIL;
+ unsigned char *result;
- zbx_timespec(&ts);
- zbx_vector_ptr_create(&history);
+ size = preprocessor_pack_test_request(&data, value_type, value, ts, history, steps);
- if (NULL != last_value)
+ if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_PREPROCESSING, ZBX_IPC_PREPROCESSOR_TEST_REQUEST,
+ SEC_PER_MIN, data, size, &result, error))
{
- const char *ptr;
- int delay;
-
- values[values_num] = last_value;
- timestamps[values_num] = ts;
-
- if (0 != strncmp(last_ts, "now", ZBX_CONST_STRLEN("now")))
- {
- *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", last_ts);
- goto out;
- }
-
- ptr = last_ts + ZBX_CONST_STRLEN("now");
-
- if ('\0' != *ptr)
- {
- if ('-' != *ptr || FAIL == is_time_suffix(ptr + 1, &delay, strlen(ptr + 1)))
- {
- *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", last_ts);
- goto out;
- }
-
- timestamps[values_num].sec -= delay;
- }
- values_num++;
+ goto out;
}
- values[values_num] = value;
- timestamps[values_num++] = ts;
-
- for (i = 0; i < values_num; i++)
- {
- unsigned char *result;
-
- zbx_free(data);
- size = preprocessor_pack_test_request(&data, value_type, values[i], &timestamps[i], &history, steps);
-
- if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_PREPROCESSING, ZBX_IPC_PREPROCESSOR_TEST_REQUEST,
- SEC_PER_MIN, data, size, &result, error))
- {
- goto out;
- }
-
- zbx_vector_ptr_clear_ext(results, (zbx_clean_func_t)zbx_preproc_result_free);
- zbx_free(*preproc_error);
- zbx_preprocessor_unpack_test_result(results, &history, preproc_error, result);
- zbx_free(result);
- }
+ zbx_preprocessor_unpack_test_result(results, history, preproc_error, result);
+ zbx_free(result);
ret = SUCCEED;
out:
- zbx_vector_ptr_clear_ext(&history, (zbx_clean_func_t)zbx_preproc_op_history_free);
- zbx_vector_ptr_destroy(&history);
-
zbx_free(data);
return ret;
}
+
diff --git a/src/zabbix_server/trapper/trapper_preproc.c b/src/zabbix_server/trapper/trapper_preproc.c
index c680323ae57..f3db01c10a3 100644
--- a/src/zabbix_server/trapper/trapper_preproc.c
+++ b/src/zabbix_server/trapper/trapper_preproc.c
@@ -23,112 +23,138 @@
#include "zbxalgo.h"
#include "preproc.h"
#include "trapper_preproc.h"
+#include "../preprocessor/preproc_history.h"
/******************************************************************************
* *
- * Function: zbx_trapper_preproc_test *
+ * Function: trapper_parse_preproc_test *
* *
- * Purpose: processes preprocessing test request *
+ * Purpose: parses preprocessing test request *
* *
- * Parameters: sock - [IN] the request source socket (frontend) *
- * jp - [IN] the request *
+ * Parameters: jp - [IN] the request *
+ * values - [OUT] the values to test optional *
+ * (history + current) *
+ * ts - [OUT] value timestamps *
+ * values_num - [OUT] the number of values *
+ * value_type - [OUT] the value type *
+ * steps - [OUT] the preprocessing steps *
+ * error - [OUT] the error message *
* *
- * Return value: SUCCEED - the request was processed successfully *
+ * Return value: SUCCEED - the request was parsed successfully *
* FAIL - otherwise *
* *
- * Comments: This function will send proper (success/fail) response to the *
- * request socket. *
- * Preprocessing failure (error returned by a preprocessing step) *
- * is counted as successful test and will return success response. *
- * *
******************************************************************************/
-int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp)
+static int trapper_parse_preproc_test(const struct zbx_json_parse *jp, char **values, zbx_timespec_t *ts,
+ int *values_num, unsigned char *value_type, zbx_vector_ptr_t *steps, int *single, char **error)
{
- char buffer[MAX_STRING_LEN], *error = NULL, *value = NULL, *last_value = NULL,
- *last_ts = NULL, *step_params = NULL, *error_handler_params = NULL,
- *preproc_error = NULL;
+ char buffer[MAX_STRING_LEN], *step_params = NULL, *error_handler_params = NULL;
+ const char *ptr;
zbx_user_t user;
- int ret = FAIL, i;
+ int ret = FAIL;
struct zbx_json_parse jp_data, jp_history, jp_steps, jp_step;
size_t size;
- unsigned char value_type, step_type, error_handler;
- zbx_vector_ptr_t steps, results;
- const char *pnext;
- struct zbx_json json;
-
- zbx_vector_ptr_create(&steps);
- zbx_vector_ptr_create(&results);
+ zbx_timespec_t ts_now;
if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_SID, buffer, sizeof(buffer)) ||
SUCCEED != DBget_user_by_active_session(buffer, &user) || USER_TYPE_ZABBIX_ADMIN > user.type)
{
- error = zbx_strdup(NULL, "Permission denied.");
+ *error = zbx_strdup(NULL, "Permission denied.");
goto out;
}
if (FAIL == zbx_json_brackets_by_name(jp, ZBX_PROTO_TAG_DATA, &jp_data))
{
- error = zbx_strdup(NULL, "Missing data field.");
- goto out;
- }
-
- size = 0;
- if (FAIL == zbx_json_value_by_name_dyn(&jp_data, ZBX_PROTO_TAG_VALUE, &value, &size))
- {
- error = zbx_strdup(NULL, "Missing value field.");
+ *error = zbx_strdup(NULL, "Missing data field.");
goto out;
}
if (FAIL == zbx_json_value_by_name(&jp_data, ZBX_PROTO_TAG_VALUE_TYPE, buffer, sizeof(buffer)))
{
- error = zbx_strdup(NULL, "Missing value type field.");
+ *error = zbx_strdup(NULL, "Missing value type field.");
goto out;
}
- value_type = atoi(buffer);
+ *value_type = atoi(buffer);
+
+ if (FAIL == zbx_json_value_by_name(&jp_data, ZBX_PROTO_TAG_SINGLE, buffer, sizeof(buffer)))
+ *single = 0;
+ else
+ *single = (0 == strcmp(buffer, "true") ? 1 : 0);
+ zbx_timespec(&ts_now);
if (SUCCEED == zbx_json_brackets_by_name(&jp_data, ZBX_PROTO_TAG_HISTORY, &jp_history))
{
size = 0;
- if (FAIL == zbx_json_value_by_name_dyn(&jp_history, ZBX_PROTO_TAG_VALUE, &last_value, &size))
+ if (FAIL == zbx_json_value_by_name_dyn(&jp_history, ZBX_PROTO_TAG_VALUE, values, &size))
{
- error = zbx_strdup(NULL, "Missing history value field.");
+ *error = zbx_strdup(NULL, "Missing history value field.");
goto out;
}
+ (*values_num)++;
- size = 0;
- if (FAIL == zbx_json_value_by_name_dyn(&jp_history, ZBX_PROTO_TAG_TIMESTAMP, &last_ts, &size))
+ if (FAIL == zbx_json_value_by_name(&jp_history, ZBX_PROTO_TAG_TIMESTAMP, buffer, sizeof(buffer)))
+ {
+ *error = zbx_strdup(NULL, "Missing history timestamp field.");
+ goto out;
+ }
+
+ if (0 != strncmp(buffer, "now", ZBX_CONST_STRLEN("now")))
{
- error = zbx_strdup(NULL, "Missing history timestamp field.");
+ *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", buffer);
goto out;
}
+
+ ts[0] = ts_now;
+ ptr = buffer + ZBX_CONST_STRLEN("now");
+
+ if ('\0' != *ptr)
+ {
+ int delay;
+
+ if ('-' != *ptr || FAIL == is_time_suffix(ptr + 1, &delay, strlen(ptr + 1)))
+ {
+ *error = zbx_dsprintf(NULL, "invalid history value timestamp: %s", buffer);
+ goto out;
+ }
+
+ ts[0].sec -= delay;
+ }
+ }
+
+ size = 0;
+ if (FAIL == zbx_json_value_by_name_dyn(&jp_data, ZBX_PROTO_TAG_VALUE, &values[*values_num], &size))
+ {
+ *error = zbx_strdup(NULL, "Missing value field.");
+ goto out;
}
+ ts[(*values_num)++] = ts_now;
if (FAIL == zbx_json_brackets_by_name(&jp_data, ZBX_PROTO_TAG_STEPS, &jp_steps))
{
- error = zbx_strdup(NULL, "Missing preprocessing steps field.");
+ *error = zbx_strdup(NULL, "Missing preprocessing steps field.");
goto out;
}
- for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp_steps, pnext));)
+ for (ptr = NULL; NULL != (ptr = zbx_json_next(&jp_steps, ptr));)
{
zbx_preproc_op_t *step;
+ unsigned char step_type, error_handler;
- if (FAIL == zbx_json_brackets_open(pnext, &jp_step))
+ if (FAIL == zbx_json_brackets_open(ptr, &jp_step))
{
- error = zbx_strdup(NULL, "Cannot parse preprocessing step.");
+ *error = zbx_strdup(NULL, "Cannot parse preprocessing step.");
goto out;
}
if (FAIL == zbx_json_value_by_name(&jp_step, ZBX_PROTO_TAG_TYPE, buffer, sizeof(buffer)))
{
- error = zbx_strdup(NULL, "Missing preprocessing step type field.");
+ *error = zbx_strdup(NULL, "Missing preprocessing step type field.");
goto out;
}
step_type = atoi(buffer);
if (FAIL == zbx_json_value_by_name(&jp_step, ZBX_PROTO_TAG_ERROR_HANDLER, buffer, sizeof(buffer)))
{
- error = zbx_strdup(NULL, "Missing preprocessing step type error handler field.");
+ *error = zbx_strdup(NULL, "Missing preprocessing step type error handler field.");
goto out;
}
error_handler = atoi(buffer);
@@ -136,7 +162,7 @@ int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp
size = 0;
if (FAIL == zbx_json_value_by_name_dyn(&jp_step, ZBX_PROTO_TAG_PARAMS, &step_params, &size))
{
- error = zbx_strdup(NULL, "Missing preprocessing step type params field.");
+ *error = zbx_strdup(NULL, "Missing preprocessing step type params field.");
goto out;
}
@@ -144,7 +170,7 @@ int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp
if (FAIL == zbx_json_value_by_name_dyn(&jp_step, ZBX_PROTO_TAG_ERROR_HANDLER_PARAMS,
&error_handler_params, &size))
{
- error = zbx_strdup(NULL, "Missing preprocessing step type error handler params field.");
+ *error = zbx_strdup(NULL, "Missing preprocessing step type error handler params field.");
goto out;
}
@@ -153,74 +179,146 @@ int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp
step->params = step_params;
step->error_handler = error_handler;
step->error_handler_params = error_handler_params;
- zbx_vector_ptr_append(&steps, step);
+ zbx_vector_ptr_append(steps, step);
step_params = NULL;
error_handler_params = NULL;
}
- if (FAIL == zbx_preprocessor_test(value_type, value, last_value, last_ts, &steps, &results, &preproc_error,
- &error))
+ ret = SUCCEED;
+out:
+ if (FAIL == ret)
{
+ zbx_vector_ptr_clear_ext(steps, (zbx_clean_func_t)zbx_preproc_op_free);
+ zbx_free(values[0]);
+ zbx_free(values[1]);
+ }
+
+ zbx_free(step_params);
+ zbx_free(error_handler_params);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_trapper_preproc_test_execute *
+ * *
+ * Purpose: executes preprocessing test request *
+ * *
+ * Parameters: jp - [IN] the request *
+ * json - [OUT] the output json *
+ * error - [OUT] the error message *
+ * *
+ * Return value: SUCCEED - the request was executed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: This function will fail if the request format is not valid or *
+ * there was connection (to preprocessing manager) error. *
+ * Any errors in the preprocessing itself are reported in output *
+ * json and success is returned. *
+ * *
+ ******************************************************************************/
+int zbx_trapper_preproc_test_run(const struct zbx_json_parse *jp, struct zbx_json *json, char **error)
+{
+ char *values[2] = {NULL, NULL}, *preproc_error = NULL;
+ int ret = FAIL, i, values_num = 0, single;
+ unsigned char value_type;
+ zbx_vector_ptr_t steps, results, history;
+ zbx_timespec_t ts[2];
+ zbx_preproc_result_t *result;
+
+ zbx_vector_ptr_create(&steps);
+ zbx_vector_ptr_create(&results);
+ zbx_vector_ptr_create(&history);
+
+ if (FAIL == trapper_parse_preproc_test(jp, values, ts, &values_num, &value_type, &steps, &single, error))
goto out;
+
+ for (i = 0; i < values_num; i++)
+ {
+ zbx_vector_ptr_clear_ext(&results, (zbx_clean_func_t)zbx_preproc_result_free);
+ if (FAIL == zbx_preprocessor_test(value_type, values[i], &ts[i], &steps, &results, &history,
+ &preproc_error, error))
+ {
+ goto out;
+ }
+
+ if (NULL != preproc_error)
+ break;
+
+ if (0 == single)
+ {
+ result = (zbx_preproc_result_t *)results.values[results.values_num - 1];
+ if (ZBX_VARIANT_NONE != result->value.type &&
+ FAIL == zbx_variant_to_value_type(&result->value, value_type, &preproc_error))
+ {
+ break;
+ }
+ }
}
- zbx_json_init(&json, results.values_num * 256);
+ zbx_json_addstring(json, ZBX_PROTO_TAG_RESPONSE, "success", ZBX_JSON_TYPE_STRING);
+ zbx_json_addobject(json, ZBX_PROTO_TAG_DATA);
- zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, "success", ZBX_JSON_TYPE_STRING);
- zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
+ if (i + 1 < values_num)
+ zbx_json_addstring(json, ZBX_PROTO_TAG_PREVIOUS, "true", ZBX_JSON_TYPE_INT);
+ zbx_json_addarray(json, ZBX_PROTO_TAG_STEPS);
for (i = 0; i < results.values_num; i++)
{
- zbx_preproc_result_t *result = (zbx_preproc_result_t *)results.values[i];
+ result = (zbx_preproc_result_t *)results.values[i];
- zbx_json_addobject(&json, NULL);
+ zbx_json_addobject(json, NULL);
if (NULL != result->error)
- zbx_json_addstring(&json, ZBX_PROTO_TAG_ERROR, result->error, ZBX_JSON_TYPE_STRING);
+ zbx_json_addstring(json, ZBX_PROTO_TAG_ERROR, result->error, ZBX_JSON_TYPE_STRING);
if (ZBX_PREPROC_FAIL_DEFAULT != result->action)
- zbx_json_adduint64(&json, ZBX_PROTO_TAG_ACTION, result->action);
+ zbx_json_adduint64(json, ZBX_PROTO_TAG_ACTION, result->action);
- if (i == results.values_num - 1 && NULL != preproc_error)
+ if (i == results.values_num - 1 && NULL != result->error)
{
if (ZBX_PREPROC_FAIL_SET_ERROR == result->action)
- zbx_json_addstring(&json, ZBX_PROTO_TAG_FAILED, preproc_error, ZBX_JSON_TYPE_STRING);
+ zbx_json_addstring(json, ZBX_PROTO_TAG_FAILED, preproc_error, ZBX_JSON_TYPE_STRING);
}
- else
+
+ if (ZBX_VARIANT_NONE != result->value.type)
{
- if (ZBX_VARIANT_NONE != result->value.type)
- {
- zbx_json_addstring(&json, ZBX_PROTO_TAG_RESULT, zbx_variant_value_desc(&result->value),
- ZBX_JSON_TYPE_STRING);
- }
- else
- zbx_json_addstring(&json, ZBX_PROTO_TAG_RESULT, NULL, ZBX_JSON_TYPE_NULL);
+ zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, zbx_variant_value_desc(&result->value),
+ ZBX_JSON_TYPE_STRING);
}
+ else if (NULL == result->error || ZBX_PREPROC_FAIL_DISCARD_VALUE == result->action)
+ zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, NULL, ZBX_JSON_TYPE_NULL);
- zbx_json_close(&json);
+ zbx_json_close(json);
}
+ zbx_json_close(json);
- zbx_tcp_send_bytes_to(sock, json.buffer, json.buffer_size, CONFIG_TIMEOUT);
+ if (NULL == preproc_error)
+ {
+ result = (zbx_preproc_result_t *)results.values[results.values_num - 1];
- zbx_json_free(&json);
+ if (ZBX_VARIANT_NONE != result->value.type)
+ {
+ zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, zbx_variant_value_desc(&result->value),
+ ZBX_JSON_TYPE_STRING);
+ }
+ else
+ zbx_json_addstring(json, ZBX_PROTO_TAG_RESULT, NULL, ZBX_JSON_TYPE_NULL);
+ }
+ else
+ zbx_json_addstring(json, ZBX_PROTO_TAG_ERROR, preproc_error, ZBX_JSON_TYPE_STRING);
ret = SUCCEED;
out:
- if (FAIL == ret)
- {
- zbx_send_response(sock, ret, error, CONFIG_TIMEOUT);
- zbx_free(error);
- }
+ for (i = 0; i < values_num; i++)
+ zbx_free(values[i]);
zbx_free(preproc_error);
- zbx_free(error);
- zbx_free(error_handler_params);
- zbx_free(step_params);
- zbx_free(last_ts);
- zbx_free(last_value);
- zbx_free(value);
+ zbx_vector_ptr_clear_ext(&history, (zbx_clean_func_t)zbx_preproc_op_history_free);
+ zbx_vector_ptr_destroy(&history);
zbx_vector_ptr_clear_ext(&results, (zbx_clean_func_t)zbx_preproc_result_free);
zbx_vector_ptr_destroy(&results);
zbx_vector_ptr_clear_ext(&steps, (zbx_clean_func_t)zbx_preproc_op_free);
@@ -228,3 +326,45 @@ out:
return ret;
}
+
+/******************************************************************************
+ * *
+ * Function: zbx_trapper_preproc_test *
+ * *
+ * Purpose: processes preprocessing test request *
+ * *
+ * Parameters: sock - [IN] the request source socket (frontend) *
+ * jp - [IN] the request *
+ * *
+ * Return value: SUCCEED - the request was processed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: This function will send proper (success/fail) response to the *
+ * request socket. *
+ * Preprocessing failure (error returned by a preprocessing step) *
+ * is counted as successful test and will return success response. *
+ * *
+ ******************************************************************************/
+int zbx_trapper_preproc_test(zbx_socket_t *sock, const struct zbx_json_parse *jp)
+{
+ char *error = NULL;
+ int ret;
+ struct zbx_json json;
+
+ zbx_json_init(&json, 1024);
+
+ if (SUCCEED == (ret = zbx_trapper_preproc_test_run(jp, &json, &error)))
+ {
+ zbx_tcp_send_bytes_to(sock, json.buffer, json.buffer_size, CONFIG_TIMEOUT);
+ }
+ else
+ {
+ zbx_send_response(sock, ret, error, CONFIG_TIMEOUT);
+ zbx_free(error);
+ }
+
+ zbx_json_free(&json);
+
+ return ret;
+}
+
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_ */