You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

412 lines
14 KiB

1 year ago
/*
** Zabbix
** Copyright (C) 2001-2023 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 "zbxcommon.h"
#include "zbxjson.h"
#include "zbxcacheconfig.h"
#include "zbxembed.h"
#include "zbxlog.h"
#include "zbxpreproc.h"
#include "libs/zbxpreproc/pp_execute.h"
#include "libs/zbxpreproc/preproc_snmp.h"
#include "libs/zbxpreproc/pp_cache.h"
#ifdef HAVE_NETSNMP
#define SNMP_NO_DEBUGGING
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#endif
static int str_to_preproc_type(const char *str)
{
if (0 == strcmp(str, "ZBX_PREPROC_MULTIPLIER"))
return ZBX_PREPROC_MULTIPLIER;
if (0 == strcmp(str, "ZBX_PREPROC_RTRIM"))
return ZBX_PREPROC_RTRIM;
if (0 == strcmp(str, "ZBX_PREPROC_LTRIM"))
return ZBX_PREPROC_LTRIM;
if (0 == strcmp(str, "ZBX_PREPROC_TRIM"))
return ZBX_PREPROC_TRIM;
if (0 == strcmp(str, "ZBX_PREPROC_REGSUB"))
return ZBX_PREPROC_REGSUB;
if (0 == strcmp(str, "ZBX_PREPROC_BOOL2DEC"))
return ZBX_PREPROC_BOOL2DEC;
if (0 == strcmp(str, "ZBX_PREPROC_OCT2DEC"))
return ZBX_PREPROC_OCT2DEC;
if (0 == strcmp(str, "ZBX_PREPROC_HEX2DEC"))
return ZBX_PREPROC_HEX2DEC;
if (0 == strcmp(str, "ZBX_PREPROC_DELTA_VALUE"))
return ZBX_PREPROC_DELTA_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_DELTA_SPEED"))
return ZBX_PREPROC_DELTA_SPEED;
if (0 == strcmp(str, "ZBX_PREPROC_XPATH"))
return ZBX_PREPROC_XPATH;
if (0 == strcmp(str, "ZBX_PREPROC_JSONPATH"))
return ZBX_PREPROC_JSONPATH;
if (0 == strcmp(str, "ZBX_PREPROC_VALIDATE_RANGE"))
return ZBX_PREPROC_VALIDATE_RANGE;
if (0 == strcmp(str, "ZBX_PREPROC_VALIDATE_REGEX"))
return ZBX_PREPROC_VALIDATE_REGEX;
if (0 == strcmp(str, "ZBX_PREPROC_VALIDATE_NOT_REGEX"))
return ZBX_PREPROC_VALIDATE_NOT_REGEX;
if (0 == strcmp(str, "ZBX_PREPROC_ERROR_FIELD_JSON"))
return ZBX_PREPROC_ERROR_FIELD_JSON;
if (0 == strcmp(str, "ZBX_PREPROC_ERROR_FIELD_XML"))
return ZBX_PREPROC_ERROR_FIELD_XML;
if (0 == strcmp(str, "ZBX_PREPROC_ERROR_FIELD_REGEX"))
return ZBX_PREPROC_ERROR_FIELD_REGEX;
if (0 == strcmp(str, "ZBX_PREPROC_THROTTLE_VALUE"))
return ZBX_PREPROC_THROTTLE_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_THROTTLE_TIMED_VALUE"))
return ZBX_PREPROC_THROTTLE_TIMED_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_PROMETHEUS_PATTERN"))
return ZBX_PREPROC_PROMETHEUS_PATTERN;
if (0 == strcmp(str, "ZBX_PREPROC_PROMETHEUS_TO_JSON"))
return ZBX_PREPROC_PROMETHEUS_TO_JSON;
if (0 == strcmp(str, "ZBX_PREPROC_CSV_TO_JSON"))
return ZBX_PREPROC_CSV_TO_JSON;
if (0 == strcmp(str, "ZBX_PREPROC_STR_REPLACE"))
return ZBX_PREPROC_STR_REPLACE;
if (0 == strcmp(str, "ZBX_PREPROC_SNMP_WALK_TO_JSON"))
return ZBX_PREPROC_SNMP_WALK_TO_JSON;
if (0 == strcmp(str, "ZBX_PREPROC_SNMP_WALK_TO_VALUE"))
return ZBX_PREPROC_SNMP_WALK_TO_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_SCRIPT"))
return ZBX_PREPROC_SCRIPT;
fail_msg("unknow preprocessing step type: %s", str);
return FAIL;
}
static int str_to_preproc_error_handler(const char *str)
{
if (0 == strcmp(str, "ZBX_PREPROC_FAIL_DEFAULT"))
return ZBX_PREPROC_FAIL_DEFAULT;
if (0 == strcmp(str, "ZBX_PREPROC_FAIL_DISCARD_VALUE"))
return ZBX_PREPROC_FAIL_DISCARD_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_FAIL_SET_VALUE"))
return ZBX_PREPROC_FAIL_SET_VALUE;
if (0 == strcmp(str, "ZBX_PREPROC_FAIL_SET_ERROR"))
return ZBX_PREPROC_FAIL_SET_ERROR;
fail_msg("unknow preprocessing error handler: %s", str);
return FAIL;
}
static void read_value(const char *path, unsigned char *value_type, zbx_variant_t *value, zbx_timespec_t *ts)
{
zbx_mock_handle_t handle;
handle = zbx_mock_get_parameter_handle(path);
if (NULL != value_type)
*value_type = zbx_mock_str_to_value_type(zbx_mock_get_object_member_string(handle, "value_type"));
zbx_strtime_to_timespec(zbx_mock_get_object_member_string(handle, "time"), ts);
zbx_variant_set_str(value, zbx_strdup(NULL, zbx_mock_get_object_member_string(handle, "data")));
}
static void read_history_value(const char *path, zbx_variant_t *value, zbx_timespec_t *ts)
{
zbx_mock_handle_t handle;
handle = zbx_mock_get_parameter_handle(path);
zbx_strtime_to_timespec(zbx_mock_get_object_member_string(handle, "time"), ts);
zbx_variant_set_str(value, zbx_strdup(NULL, zbx_mock_get_object_member_string(handle, "data")));
zbx_variant_convert(value, zbx_mock_str_to_variant(zbx_mock_get_object_member_string(handle, "variant")));
}
static void read_step(const char *path, zbx_pp_step_t *step)
{
zbx_mock_handle_t hop, hop_params, herror, herror_params;
hop = zbx_mock_get_parameter_handle(path);
step->type = str_to_preproc_type(zbx_mock_get_object_member_string(hop, "type"));
if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(hop, "params", &hop_params))
step->params = (char *)zbx_mock_get_object_member_string(hop, "params");
else
step->params = "";
if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(hop, "error_handler", &herror))
step->error_handler = str_to_preproc_error_handler(
zbx_mock_get_object_member_string(hop, "error_handler"));
else
step->error_handler = ZBX_PREPROC_FAIL_DEFAULT;
if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(hop, "error_handler_params", &herror_params))
step->error_handler_params = (char *)zbx_mock_get_object_member_string(hop, "error_handler_params");
else
step->error_handler_params = "";
}
/******************************************************************************
* *
* Purpose: checks if the preprocessing step is supported based on build *
* configuration or other settings *
* *
* Parameters: type [IN] the preprocessing step type *
* *
* Return value: SUCCEED - the preprocessing step is supported *
* FAIL - the preprocessing step is not supported and will *
* always fail *
* *
******************************************************************************/
static int is_step_supported(int type)
{
switch (type)
{
case ZBX_PREPROC_XPATH:
case ZBX_PREPROC_ERROR_FIELD_XML:
#ifdef HAVE_LIBXML2
return SUCCEED;
#else
return FAIL;
#endif
default:
return SUCCEED;
}
}
#ifdef HAVE_NETSNMP
/******************************************************************************
* *
* Purpose: checks if MIB can be translated to OID by the system. Absence of *
* MIB files in the system will cause failures of MIB translation *
* tests, and such tests should be skipped if MIB was not found. *
* configuration or other settings *
* *
* Parameters: op [IN] the preprocessing step operation *
* *
* Return value: SUCCEED - MIB can be translated / MIB file exists *
* FAIL - MIB cannot be translated / MIB file doesn't exist *
* *
******************************************************************************/
static int check_mib_existence(zbx_pp_step_t *op)
{
int ret = FAIL;
oid oid_tmp[MAX_OID_LEN];
size_t oid_len = MAX_OID_LEN;
char *oid_str = NULL, *right = NULL;
if (ZBX_PREPROC_SNMP_WALK_TO_VALUE == op->type)
{
zbx_strsplit_first(op->params, '\n', &oid_str, &right);
}
else if (ZBX_PREPROC_SNMP_WALK_TO_JSON == op->type)
{
char *ptr = op->params;
int line_idx = 0;
while (line_idx != 1 && '\0' != *ptr)
{
if ('\n' == *ptr)
line_idx++;
ptr++;
}
zbx_strsplit_first(ptr, '\n', &oid_str, &right);
}
else
fail_msg("processing operation type %i is not compatible with SNMP preprocessing", op->type);
if (0 != get_node(oid_str, oid_tmp, &oid_len))
ret = SUCCEED;
zbx_free(oid_str);
zbx_free(right);
return ret;
}
#endif
void zbx_mock_test_entry(void **state)
{
zbx_variant_t value, value_in, history_value, history_value_in;
unsigned char value_type;
zbx_timespec_t ts, history_ts, history_ts_in, expected_history_ts;
zbx_pp_step_t step;
int returned_ret, expected_ret, i;
zbx_pp_context_t ctx = {0};
zbx_pp_cache_t *cache, *step_cache;
zbx_pp_item_preproc_t preproc;
#ifdef HAVE_NETSNMP
int mib_translation_case = 0;
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("in.netsnmp_required"))
mib_translation_case = 1;
#else
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("in.netsnmp_required"))
skip();
#endif
#if !defined(HAVE_OPENSSL) && !defined(HAVE_GNUTLS)
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("in.encryption_required"))
skip();
#endif
ZBX_UNUSED(state);
read_step("in.step", &step);
#ifdef HAVE_NETSNMP
preproc_init_snmp();
/* MIB translation test cases will fail if system lacks MIBs - in this case test case should be skipped */
if (1 == mib_translation_case && FAIL == check_mib_existence(&step))
{
preproc_shutdown_snmp();
skip();
}
#endif
pp_context_init(&ctx);
read_value("in.value", &value_type, &value_in, &ts);
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("in.history"))
{
read_history_value("in.history", &history_value_in, &history_ts_in);
}
else
{
zbx_variant_set_none(&history_value_in);
history_ts_in.sec = 0;
history_ts_in.ns = 0;
}
preproc.steps = &step;
preproc.steps_num = 1;
cache = pp_cache_create(&preproc, &value_in);
for (i = 0; i < 4; i++)
{
zbx_variant_copy(&value, &value_in);
zbx_variant_copy(&history_value, &history_value_in);
history_ts = history_ts_in;
/* run first and last test with no cache */
if (0 == i || 3 == i || SUCCEED != pp_cache_is_supported(&preproc))
step_cache = NULL;
else
step_cache = cache;
if (FAIL == (returned_ret = pp_execute_step(&ctx, step_cache, NULL, 0, value_type, &value, ts, &step,
&history_value, &history_ts, get_zbx_config_source_ip())))
{
pp_error_on_fail(&value, &step);
if (ZBX_VARIANT_ERR != value.type)
returned_ret = SUCCEED;
}
if (SUCCEED != returned_ret && ZBX_VARIANT_ERR == value.type)
{
zabbix_log(LOG_LEVEL_DEBUG, "Preprocessing error: %s", value.data.err);
}
if (SUCCEED == is_step_supported(step.type))
expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
else
expected_ret = FAIL;
zbx_mock_assert_result_eq("zbx_item_preproc() return", expected_ret, returned_ret);
if (SUCCEED == returned_ret)
{
if (SUCCEED == is_step_supported(step.type) &&
ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("out.error"))
{
zbx_mock_assert_int_eq("result variant type", ZBX_VARIANT_ERR, value.type);
}
else
{
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("out.value"))
{
if (ZBX_VARIANT_NONE == value.type)
fail_msg("preprocessing result was empty value");
if (ZBX_VARIANT_DBL == value.type)
{
zbx_mock_assert_double_eq("processed value",
atof(zbx_mock_get_parameter_string("out.value")),
value.data.dbl);
}
else
{
zbx_variant_convert(&value, ZBX_VARIANT_STR);
zbx_mock_assert_str_eq("processed value",
zbx_mock_get_parameter_string("out.value"), value.data.str);
}
}
else
{
if (ZBX_VARIANT_NONE != value.type)
fail_msg("expected empty value, but got %s", zbx_variant_value_desc(&value));
}
if (ZBX_MOCK_SUCCESS == zbx_mock_parameter_exists("out.history"))
{
if (ZBX_VARIANT_NONE == history_value.type)
fail_msg("preprocessing history was empty value");
zbx_variant_convert(&history_value, ZBX_VARIANT_STR);
zbx_mock_assert_str_eq("preprocessing step history value",
zbx_mock_get_parameter_string("out.history.data"),
history_value.data.str);
zbx_strtime_to_timespec(zbx_mock_get_parameter_string("out.history.time"),
&expected_history_ts);
zbx_mock_assert_timespec_eq("preprocessing step history time", &expected_history_ts,
&history_ts);
}
else
{
/* history_value will contain duktape bytecode if step is a script */
if (ZBX_VARIANT_NONE != history_value.type && ZBX_PREPROC_SCRIPT != step.type)
{
fail_msg("expected empty history, but got %s",
zbx_variant_value_desc(&history_value));
}
}
}
}
else
zbx_mock_assert_int_eq("result variant type", ZBX_VARIANT_ERR, value.type);
zbx_variant_clear(&value);
zbx_variant_clear(&history_value);
}
pp_cache_release(cache);
zbx_variant_clear(&value_in);
zbx_variant_clear(&history_value_in);
pp_context_destroy(&ctx);
#ifdef HAVE_NETSNMP
preproc_shutdown_snmp();
#endif
}