diff options
-rw-r--r-- | include/common.h | 2 | ||||
-rw-r--r-- | include/zbxserver.h | 3 | ||||
-rw-r--r-- | include/zbxtrends.h | 4 | ||||
-rw-r--r-- | src/libs/zbxcommon/time.c | 14 | ||||
-rw-r--r-- | src/libs/zbxdbcache/dbconfig.c | 8 | ||||
-rw-r--r-- | src/libs/zbxdbhigh/trigger.c | 32 | ||||
-rw-r--r-- | src/libs/zbxeval/eval.h | 27 | ||||
-rw-r--r-- | src/libs/zbxserver/Makefile.am | 3 | ||||
-rw-r--r-- | src/libs/zbxserver/evalfunc.c | 163 | ||||
-rw-r--r-- | src/libs/zbxserver/evalfunc2.c | 2293 | ||||
-rw-r--r-- | src/libs/zbxserver/expression.c | 2 | ||||
-rw-r--r-- | src/libs/zbxtrends/trends.c | 167 | ||||
-rw-r--r-- | tests/libs/zbxcommon/zbx_tm_add.yaml | 48 | ||||
-rw-r--r-- | tests/libs/zbxcommon/zbx_tm_round_down.yaml | 16 | ||||
-rw-r--r-- | tests/libs/zbxcommon/zbx_tm_round_up.yaml | 16 | ||||
-rw-r--r-- | tests/libs/zbxcommon/zbx_tm_sub.yaml | 32 | ||||
-rw-r--r-- | tests/libs/zbxserver/evaluate_function.c | 4 | ||||
-rw-r--r-- | tests/libs/zbxserver/evaluate_function.yaml | 795 | ||||
-rw-r--r-- | tests/libs/zbxtrends/zbx_trends_parse_range.c | 7 | ||||
-rw-r--r-- | tests/libs/zbxtrends/zbx_trends_parse_range.yaml | 134 | ||||
-rw-r--r-- | ui/include/defines.inc.php | 2 |
21 files changed, 2939 insertions, 833 deletions
diff --git a/include/common.h b/include/common.h index 13beaf1acd8..3e21d92d70b 100644 --- a/include/common.h +++ b/include/common.h @@ -1646,6 +1646,8 @@ int zbx_str_extract(const char *text, size_t len, char **value); typedef enum { ZBX_TIME_UNIT_UNKNOWN, + ZBX_TIME_UNIT_SECOND, + ZBX_TIME_UNIT_MINUTE, ZBX_TIME_UNIT_HOUR, ZBX_TIME_UNIT_DAY, ZBX_TIME_UNIT_WEEK, diff --git a/include/zbxserver.h b/include/zbxserver.h index da0778313cf..8076dddfa67 100644 --- a/include/zbxserver.h +++ b/include/zbxserver.h @@ -62,6 +62,9 @@ void get_functionids(zbx_vector_uint64_t *functionids, const char *expression); int evaluate_function(char **value, DC_ITEM *item, const char *function, const char *parameter, const zbx_timespec_t *ts, char **error); +int evaluate_function2(char **value, DC_ITEM *item, const char *function, const char *parameter, + const zbx_timespec_t *ts, char **error); + int substitute_simple_macros(zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event, zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item, diff --git a/include/zbxtrends.h b/include/zbxtrends.h index a99b587af94..33ed4387d14 100644 --- a/include/zbxtrends.h +++ b/include/zbxtrends.h @@ -25,9 +25,9 @@ #include "dbcache.h" int zbx_trends_parse_base(const char *params, zbx_time_unit_t *base, char **error); +int zbx_parse_timeshift(time_t from, const char *timeshift, struct tm *tm, char **error); -int zbx_trends_parse_range(time_t from, const char *period, const char *period_shift, int *start, int *end, - char **error); +int zbx_trends_parse_range(time_t from, const char *param, int *start, int *end, char **error); int zbx_trends_parse_nextcheck(time_t from, const char *period_shift, time_t *nextcheck, char **error); int zbx_trends_eval_avg(const char *table, zbx_uint64_t itemid, int start, int end, double *value, char **error); diff --git a/src/libs/zbxcommon/time.c b/src/libs/zbxcommon/time.c index b5864e2837b..170d7c26f90 100644 --- a/src/libs/zbxcommon/time.c +++ b/src/libs/zbxcommon/time.c @@ -22,12 +22,17 @@ static void tm_add(struct tm *tm, int multiplier, zbx_time_unit_t base); static void tm_sub(struct tm *tm, int multiplier, zbx_time_unit_t base); -static int time_unit_seconds[ZBX_TIME_UNIT_COUNT] = {0, SEC_PER_HOUR, SEC_PER_DAY, SEC_PER_WEEK, 0, 0}; +static int time_unit_seconds[ZBX_TIME_UNIT_COUNT] = {0, 1, SEC_PER_MIN, SEC_PER_HOUR, SEC_PER_DAY, SEC_PER_WEEK, 0, + 0}; zbx_time_unit_t zbx_tm_str_to_unit(const char *text) { switch (*text) { + case 's': + return ZBX_TIME_UNIT_SECOND; + case 'm': + return ZBX_TIME_UNIT_MINUTE; case 'h': return ZBX_TIME_UNIT_HOUR; case 'd': @@ -315,9 +320,12 @@ void zbx_tm_round_up(struct tm *tm, zbx_time_unit_t base) if (0 != tm->tm_sec) { tm->tm_sec = 0; - tm->tm_min++; + zbx_tm_add(tm, 1, ZBX_TIME_UNIT_MINUTE); } + if (ZBX_TIME_UNIT_MINUTE == base) + return; + if (0 != tm->tm_min) { tm->tm_min = 0; @@ -400,6 +408,8 @@ void zbx_tm_round_down(struct tm *tm, zbx_time_unit_t base) ZBX_FALLTHROUGH; case ZBX_TIME_UNIT_HOUR: tm->tm_min = 0; + ZBX_FALLTHROUGH; + case ZBX_TIME_UNIT_MINUTE: tm->tm_sec = 0; break; default: diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c index 64b074dae0e..062e7b05788 100644 --- a/src/libs/zbxdbcache/dbconfig.c +++ b/src/libs/zbxdbcache/dbconfig.c @@ -3925,11 +3925,11 @@ static int dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, tim { struct tm tm; time_t nextcheck; - int offsets[ZBX_TIME_UNIT_COUNT] = {0, SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10, + int offsets[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10, - SEC_PER_HOUR + SEC_PER_MIN * 10}; - int periods[ZBX_TIME_UNIT_COUNT] = {0, SEC_PER_MIN * 10, SEC_PER_HOUR, SEC_PER_HOUR * 11, - SEC_PER_DAY - SEC_PER_HOUR, SEC_PER_DAY - SEC_PER_HOUR}; + SEC_PER_HOUR + SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10}; + int periods[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, SEC_PER_MIN * 10, SEC_PER_HOUR, + SEC_PER_HOUR * 11, SEC_PER_DAY - SEC_PER_HOUR, SEC_PER_DAY - SEC_PER_HOUR}; if (ZBX_TIME_UNIT_HOUR == timer->trend_base) { diff --git a/src/libs/zbxdbhigh/trigger.c b/src/libs/zbxdbhigh/trigger.c index 82078904c9d..56cd6c45dd0 100644 --- a/src/libs/zbxdbhigh/trigger.c +++ b/src/libs/zbxdbhigh/trigger.c @@ -32,15 +32,6 @@ #define ZBX_FLAGS_TRIGGER_CREATE_EVENT \ (ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT | ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT) -/* DB_TRIGGER cached objects */ -typedef enum -{ - ZBX_DB_TRIGGER_CACHE_EVAL_CTX, - ZBX_DB_TRIGGER_CACHE_EVAL_CTX_R, - ZBX_DB_TRIGGER_CACHE_EVAL_CTX_MACROS, -} -zbx_db_trigger_cache_t; - /****************************************************************************** * * * Function: zbx_process_trigger * @@ -316,7 +307,8 @@ void zbx_append_trigger_diff(zbx_vector_ptr_t *trigger_diff, zbx_uint64_t trigge /* temporary cache of trigger related data */ typedef struct { - zbx_uint64_t flags; + zbx_uint32_t init; + zbx_uint32_t done; zbx_eval_context_t eval_ctx; zbx_eval_context_t eval_ctx_r; zbx_vector_uint64_t hostids; @@ -347,22 +339,22 @@ static zbx_trigger_cache_t *db_trigger_get_cache(const DB_TRIGGER *trigger, zbx_ { zbx_trigger_cache_t *cache; char *error = NULL; - zbx_uint64_t flag = __UINT64_C(1) << state; + zbx_uint32_t flag = 1 << state; zbx_vector_uint64_t functionids; if (NULL == trigger->cache) { cache = (zbx_trigger_cache_t *)zbx_malloc(NULL, sizeof(zbx_trigger_cache_t)); - cache->flags = 0; + cache->init = cache->done = 0; ((DB_TRIGGER *)trigger)->cache = cache; } else cache = (zbx_trigger_cache_t *)trigger->cache; - if (0 != (cache->flags & flag)) - return 0 != (cache->flags & (flag << 32)) ? cache : NULL; + if (0 != (cache->init & flag)) + return 0 != (cache->done & flag) ? cache : NULL; - cache->flags |= flag; + cache->init |= flag; switch (state) { @@ -388,7 +380,7 @@ static zbx_trigger_cache_t *db_trigger_get_cache(const DB_TRIGGER *trigger, zbx_ return NULL; } break; - case ZBX_DB_TRIGGER_CACHE_EVAL_CTX_MACROS: + case ZBX_TRIGGER_CACHE_EVAL_CTX_MACROS: if (NULL == db_trigger_get_cache(trigger, ZBX_TRIGGER_CACHE_EVAL_CTX)) return NULL; zbx_dc_eval_expand_user_macros(&cache->eval_ctx); @@ -404,7 +396,7 @@ static zbx_trigger_cache_t *db_trigger_get_cache(const DB_TRIGGER *trigger, zbx_ return NULL; } - cache->flags |= (flag << 32); + cache->done |= flag; return cache; } @@ -420,13 +412,13 @@ static zbx_trigger_cache_t *db_trigger_get_cache(const DB_TRIGGER *trigger, zbx_ ******************************************************************************/ static void trigger_cache_free(zbx_trigger_cache_t *cache) { - if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_EVAL_CTX << 32))) + if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_EVAL_CTX))) zbx_eval_clear(&cache->eval_ctx); - if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_EVAL_CTX_R << 32))) + if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_EVAL_CTX_R))) zbx_eval_clear(&cache->eval_ctx_r); - if (0 != (cache->flags & (__UINT64_C(1) << ZBX_TRIGGER_CACHE_HOSTIDS << 32))) + if (0 != (cache->done & (1 << ZBX_TRIGGER_CACHE_HOSTIDS))) zbx_vector_uint64_destroy(&cache->hostids); zbx_free(cache); diff --git a/src/libs/zbxeval/eval.h b/src/libs/zbxeval/eval.h new file mode 100644 index 00000000000..0439d7db87b --- /dev/null +++ b/src/libs/zbxeval/eval.h @@ -0,0 +1,27 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 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_EVAL_H +#define ZABBIX_EVAL_H + +#include "common.h" + +int eval_compare_token(const zbx_eval_context_t *ctx, const zbx_strloc_t *loc, const char *text, + size_t len); +#endif diff --git a/src/libs/zbxserver/Makefile.am b/src/libs/zbxserver/Makefile.am index c6c5253be7c..3a651e9b08a 100644 --- a/src/libs/zbxserver/Makefile.am +++ b/src/libs/zbxserver/Makefile.am @@ -9,7 +9,8 @@ libzbxserver_a_SOURCES = \ macrofunc.c \ macrofunc.h \ zabbix_stats.c \ - zabbix_stats.h + zabbix_stats.h \ + evalfunc2.c libzbxserver_server_a_SOURCES = \ zabbix_stats.h \ diff --git a/src/libs/zbxserver/evalfunc.c b/src/libs/zbxserver/evalfunc.c index 812aa9e3a99..df63045a3f6 100644 --- a/src/libs/zbxserver/evalfunc.c +++ b/src/libs/zbxserver/evalfunc.c @@ -2697,6 +2697,167 @@ out: /****************************************************************************** * * + * Function: trends_parse_range * + * * + * Purpose: parse trend function period arguments into time range using old * + * parameter format * + * * + * Parameters: from - [IN] the time the period shift is calculated * + * from * + * period - [IN] the history period * + * period_shift - [IN] the history period shift * + * start - [OUT] the period start time in seconds since * + * Epoch * + * end - [OUT] the period end time in seconds since * + * Epoch * + * error - [OUT] the error message if parsing failed * + * * + * Return value: SUCCEED - period was parsed successfully * + * FAIL - invalid time period was specified * + * * + * Comments: Daylight saving changes are applied when parsing ranges with * + * day+ used as period base (now/?). * + * * + * Example period_shift values: * + * now/d * + * now/d-1h * + * now/d+1h * + * now/d+1h/w * + * now/d/w/h+1h+2h * + * now-1d/h * + * * + * Comments: This is temporary solution to keep calculated checks working * + * until they are updated. * + * * + ******************************************************************************/ +static int trends_parse_range(time_t from, const char *period, const char *period_shift, int *start, int *end, + char **error) +{ + int period_num, period_hours[ZBX_TIME_UNIT_COUNT] = {0, 1, 24, 24 * 7, 24 * 30, 24 * 365}; + zbx_time_unit_t period_unit; + size_t len; + struct tm tm_end, tm_start; + const char *p; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() period:%s shift:%s", __func__, period, period_shift); + + /* parse period */ + + if (SUCCEED != zbx_tm_parse_period(period, &len, &period_num, &period_unit, error)) + return FAIL; + + if ('\0' != period[len]) + { + *error = zbx_dsprintf(*error, "unexpected character[s] in period \"%s\"", period + len); + return FAIL; + } + + if (period_hours[period_unit] * period_num > 24 * 366) + { + *error = zbx_strdup(*error, "period is too large"); + return FAIL; + } + + /* parse period shift */ + + p = period_shift; + + if (0 != strncmp(p, "now", ZBX_CONST_STRLEN("now"))) + { + *error = zbx_strdup(*error, "period shift must begin with \"now\""); + return FAIL; + } + + p += ZBX_CONST_STRLEN("now"); + + localtime_r(&from, &tm_end); + + while ('\0' != *p) + { + zbx_time_unit_t unit; + + if ('/' == *p) + { + if (ZBX_TIME_UNIT_UNKNOWN == (unit = zbx_tm_str_to_unit(++p))) + { + *error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p); + return FAIL; + } + + if (unit < period_unit) + { + *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal" + " to period time unit"); + return FAIL; + } + + zbx_tm_round_down(&tm_end, unit); + + /* unit is single character */ + p++; + } + else if ('+' == *p || '-' == *p) + { + int num; + char op = *(p++); + + if (FAIL == zbx_tm_parse_period(p, &len, &num, &unit, error)) + return FAIL; + + if (unit < period_unit) + { + *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal" + " to period time unit"); + return FAIL; + } + + if ('+' == op) + zbx_tm_add(&tm_end, num, unit); + else + zbx_tm_sub(&tm_end, num, unit); + + p += len; + } + else + { + *error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p); + return FAIL; + } + } + + tm_start = tm_end; + + /* trends clock refers to the beginning of the hourly interval - subtract */ + /* one hour to get the trends clock for the last hourly interval */ + zbx_tm_sub(&tm_end, 1, ZBX_TIME_UNIT_HOUR); + + if (-1 == (*end = mktime(&tm_end))) + { + *error = zbx_dsprintf(*error, "cannot calculate the period end time: %s", zbx_strerror(errno)); + return FAIL; + } + + if (abs((int)from - *end) > SEC_PER_YEAR * 26) + { + *error = zbx_strdup(*error, "period shift is too large"); + return FAIL; + } + + zbx_tm_sub(&tm_start, period_num, period_unit); + if (-1 == (*start = mktime(&tm_start))) + { + *error = zbx_dsprintf(*error, "cannot calculate the period start time: %s", zbx_strerror(errno)); + return FAIL; + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() start:%d end:%d", __func__, *start, *end); + + return SUCCEED; +} + + +/****************************************************************************** + * * * Function: evaluate_TREND * * * * Purpose: evaluate trend* functions for the item * @@ -2735,7 +2896,7 @@ static int evaluate_TREND(char **value, DC_ITEM *item, const char *func, const c goto out; } - if (SUCCEED != zbx_trends_parse_range(ts->sec, period, period_shift, &start, &end, error)) + if (SUCCEED != trends_parse_range(ts->sec, period, period_shift, &start, &end, error)) goto out; switch (item->value_type) diff --git a/src/libs/zbxserver/evalfunc2.c b/src/libs/zbxserver/evalfunc2.c new file mode 100644 index 00000000000..d253b6ca0a3 --- /dev/null +++ b/src/libs/zbxserver/evalfunc2.c @@ -0,0 +1,2293 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 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. +**/ + +/* + * NOTE!!!!! + * + * This is temporary update of trigger functions to support changes introduced + * with new expression syntax. + * The old functions must be kept to avoid breaking calculated and aggregate checks. + * After those are updated, this code must be copied over the old implementation and + * unused code removed. + */ + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zbxserver.h" +#include "valuecache.h" +#include "evalfunc.h" +#include "zbxregexp.h" +#include "zbxtrends.h" + +typedef enum +{ + ZBX_PARAM_OPTIONAL, + ZBX_PARAM_MANDATORY +} +zbx_param_type_t; + +typedef enum +{ + ZBX_VALUE_NONE, + ZBX_VALUE_SECONDS, + ZBX_VALUE_NVALUES +} +zbx_value_type_t; + +static const char *zbx_type_string(zbx_value_type_t type) +{ + switch (type) + { + case ZBX_VALUE_SECONDS: + return "sec"; + case ZBX_VALUE_NVALUES: + return "num"; + default: + THIS_SHOULD_NEVER_HAPPEN; + return "unknown"; + } +} + +/****************************************************************************** + * * + * Function: get_function_parameter_int * + * * + * Purpose: get the value of sec|#num trigger function parameter * + * * + * Parameters: parameters - [IN] trigger function parameters * + * Nparam - [IN] specifies which parameter to extract * + * parameter_type - [IN] specifies whether parameter is mandatory * + * or optional * + * value - [OUT] parameter value (preserved as is if the * + * parameter is optional and empty) * + * type - [OUT] parameter value type (number of seconds * + * or number of values) * + * * + * Return value: SUCCEED - parameter is valid * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int get_function_parameter_int(const char *parameters, int Nparam, zbx_param_type_t parameter_type, + int *value, zbx_value_type_t *type) +{ + char *parameter; + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam); + + if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam))) + goto out; + + if ('\0' == *parameter) + { + switch (parameter_type) + { + case ZBX_PARAM_OPTIONAL: + ret = SUCCEED; + break; + case ZBX_PARAM_MANDATORY: + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + } + else if ('#' == *parameter) + { + *type = ZBX_VALUE_NVALUES; + if (SUCCEED == is_uint31(parameter + 1, value) && 0 < *value) + ret = SUCCEED; + } + else if ('-' == *parameter) + { + if (SUCCEED == is_time_suffix(parameter + 1, value, ZBX_LENGTH_UNLIMITED)) + { + *value = -(*value); + *type = ZBX_VALUE_SECONDS; + ret = SUCCEED; + } + } + else if (SUCCEED == is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED)) + { + *type = ZBX_VALUE_SECONDS; + ret = SUCCEED; + } + + if (SUCCEED == ret) + zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d", __func__, zbx_type_string(*type), *value); + + zbx_free(parameter); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static int get_function_parameter_uint64(const char *parameters, int Nparam, zbx_uint64_t *value) +{ + char *parameter; + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam); + + if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam))) + goto out; + + if (SUCCEED == (ret = is_uint64(parameter, value))) + zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_UI64, __func__, *value); + + zbx_free(parameter); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static int get_function_parameter_float(const char *parameters, int Nparam, unsigned char flags, double *value) +{ + char *parameter; + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam); + + if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam))) + goto out; + + if (SUCCEED == (ret = is_double_suffix(parameter, flags))) + { + *value = str2double(parameter); + zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_DBL, __func__, *value); + } + + zbx_free(parameter); +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static int get_function_parameter_str(const char *parameters, int Nparam, char **value) +{ + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam); + + if (NULL == (*value = zbx_function_get_param_dyn(parameters, Nparam))) + goto out; + + zabbix_log(LOG_LEVEL_DEBUG, "%s() value:'%s'", __func__, *value); + ret = SUCCEED; +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: get_function_parameter_hist_range * + * * + * Purpose: get the value of sec|num + timeshift trigger function parameter * + * * + * Parameters: from - [IN] the function calculation time * + * parameters - [IN] trigger function parameters * + * Nparam - [IN] specifies which parameter to extract * + * value - [OUT] parameter value (preserved as is if the * + * parameter is optional and empty) * + * type - [OUT] parameter value type (number of seconds * + * or number of values) * + * timeshift - [OUT] the timeshift value (0 if absent) * + * * + * Return value: SUCCEED - parameter is valid * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int get_function_parameter_hist_range(time_t from, const char *parameters, int Nparam, int *value, + zbx_value_type_t *type, int *timeshift) +{ + char *parameter = NULL, *shift; + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam); + + if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam))) + goto out; + + if (NULL != (shift = strchr(parameter, ':'))) + *shift++ = '\0'; + + if ('\0' == *parameter) + { + *value = 0; + *type = ZBX_VALUE_NONE; + } + else if (0 == isdigit(parameter[strlen(parameter) - 1])) + { + if (SUCCEED != is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED) || 0 > *value) + goto out; + + *type = ZBX_VALUE_SECONDS; + } + else + { + if (SUCCEED != is_uint31(parameter, value)) + goto out; + *type = ZBX_VALUE_NVALUES; + } + + if (NULL != shift) + { + struct tm tm; + char *error = NULL; + time_t end; + + if (SUCCEED != zbx_parse_timeshift(from, shift, &tm, &error)) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s() timeshift error:%s", __func__, error); + zbx_free(error); + goto out; + } + + if (-1 == (end = mktime(&tm))) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s() invalid timeshift value:%s", __func__, zbx_strerror(errno)); + goto out; + } + + if (end >= from) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s() timeshift produced time in future", __func__); + goto out; + } + + *timeshift = from - end; + } + else + *timeshift = 0; + + ret = SUCCEED; + zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d timeshift:%d", __func__, zbx_type_string(*type), *value, + *timeshift); +out: + zbx_free(parameter); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_LOGEVENTID * + * * + * Purpose: evaluate function 'logeventid' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - regex string for event id matching * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_LOGEVENTID(char **value, DC_ITEM *item, const char *parameters, + const zbx_timespec_t *ts, char **error) +{ + char *arg1 = NULL; + int ret = FAIL; + zbx_vector_ptr_t regexps; + zbx_history_record_t vc_value; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(®exps); + + if (ITEM_VALUE_TYPE_LOG != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 < num_param(parameters)) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_str(parameters, 1, &arg1)) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if ('@' == *arg1) + { + DCget_expressions_by_name(®exps, arg1 + 1); + + if (0 == regexps.values_num) + { + *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg1 + 1); + goto out; + } + } + + if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value)) + { + char logeventid[16]; + int regexp_ret; + + zbx_snprintf(logeventid, sizeof(logeventid), "%d", vc_value.value.log->logeventid); + + if (FAIL == (regexp_ret = regexp_match_ex(®exps, logeventid, arg1, ZBX_CASE_SENSITIVE))) + { + *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", arg1); + } + else + { + if (ZBX_REGEXP_MATCH == regexp_ret) + *value = zbx_strdup(*value, "1"); + else if (ZBX_REGEXP_NO_MATCH == regexp_ret) + *value = zbx_strdup(*value, "0"); + + ret = SUCCEED; + } + + zbx_history_record_clear(&vc_value, item->value_type); + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for LOGEVENTID is empty"); + *error = zbx_strdup(*error, "cannot get values from value cache"); + } +out: + zbx_free(arg1); + + zbx_regexp_clean_expressions(®exps); + zbx_vector_ptr_destroy(®exps); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_LOGSOURCE * + * * + * Purpose: evaluate function 'logsource' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - ignored * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_LOGSOURCE(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + char *arg1 = NULL; + int ret = FAIL; + zbx_vector_ptr_t regexps; + zbx_history_record_t vc_value; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(®exps); + + if (ITEM_VALUE_TYPE_LOG != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 < num_param(parameters)) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_str(parameters, 1, &arg1)) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if ('@' == *arg1) + { + DCget_expressions_by_name(®exps, arg1 + 1); + + if (0 == regexps.values_num) + { + *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg1 + 1); + goto out; + } + } + + if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value)) + { + switch (regexp_match_ex(®exps, vc_value.value.log->source, arg1, ZBX_CASE_SENSITIVE)) + { + case ZBX_REGEXP_MATCH: + *value = zbx_strdup(*value, "1"); + ret = SUCCEED; + break; + case ZBX_REGEXP_NO_MATCH: + *value = zbx_strdup(*value, "0"); + ret = SUCCEED; + break; + case FAIL: + *error = zbx_dsprintf(*error, "invalid regular expression"); + } + + zbx_history_record_clear(&vc_value, item->value_type); + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSOURCE is empty"); + *error = zbx_strdup(*error, "cannot get values from value cache"); + } +out: + zbx_free(arg1); + + zbx_regexp_clean_expressions(®exps); + zbx_vector_ptr_destroy(®exps); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_LOGSEVERITY * + * * + * Purpose: evaluate function 'logseverity' for the item * + * * + * Parameters: item - item (performance metric) * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_LOGSEVERITY(char **value, DC_ITEM *item, const zbx_timespec_t *ts, char **error) +{ + int ret = FAIL; + zbx_history_record_t vc_value; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (ITEM_VALUE_TYPE_LOG != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value)) + { + size_t value_alloc = 0, value_offset = 0; + + zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", vc_value.value.log->severity); + zbx_history_record_clear(&vc_value, item->value_type); + + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSEVERITY is empty"); + *error = zbx_strdup(*error, "cannot get value from value cache"); + } +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +#define OP_UNKNOWN -1 +#define OP_EQ 0 +#define OP_NE 1 +#define OP_GT 2 +#define OP_GE 3 +#define OP_LT 4 +#define OP_LE 5 +#define OP_LIKE 6 +#define OP_REGEXP 7 +#define OP_IREGEXP 8 +#define OP_BAND 9 +#define OP_MAX 10 + +static void count_one_ui64(int *count, int op, zbx_uint64_t value, zbx_uint64_t pattern, zbx_uint64_t mask) +{ + switch (op) + { + case OP_EQ: + if (value == pattern) + (*count)++; + break; + case OP_NE: + if (value != pattern) + (*count)++; + break; + case OP_GT: + if (value > pattern) + (*count)++; + break; + case OP_GE: + if (value >= pattern) + (*count)++; + break; + case OP_LT: + if (value < pattern) + (*count)++; + break; + case OP_LE: + if (value <= pattern) + (*count)++; + break; + case OP_BAND: + if ((value & mask) == pattern) + (*count)++; + } +} + +static void count_one_dbl(int *count, int op, double value, double pattern) +{ + switch (op) + { + case OP_EQ: + if (value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON) + (*count)++; + break; + case OP_NE: + if (!(value > pattern - ZBX_DOUBLE_EPSILON && value < pattern + ZBX_DOUBLE_EPSILON)) + (*count)++; + break; + case OP_GT: + if (value >= pattern + ZBX_DOUBLE_EPSILON) + (*count)++; + break; + case OP_GE: + if (value > pattern - ZBX_DOUBLE_EPSILON) + (*count)++; + break; + case OP_LT: + if (value <= pattern - ZBX_DOUBLE_EPSILON) + (*count)++; + break; + case OP_LE: + if (value < pattern + ZBX_DOUBLE_EPSILON) + (*count)++; + } +} + +static void count_one_str(int *count, int op, const char *value, const char *pattern, zbx_vector_ptr_t *regexps) +{ + int res; + + switch (op) + { + case OP_EQ: + if (0 == strcmp(value, pattern)) + (*count)++; + break; + case OP_NE: + if (0 != strcmp(value, pattern)) + (*count)++; + break; + case OP_LIKE: + if (NULL != strstr(value, pattern)) + (*count)++; + break; + case OP_REGEXP: + if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE))) + (*count)++; + else if (FAIL == res) + *count = FAIL; + break; + case OP_IREGEXP: + if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_IGNORE_CASE))) + (*count)++; + else if (FAIL == res) + *count = FAIL; + } +} + +/****************************************************************************** + * * + * Function: evaluate_COUNT * + * * + * Purpose: evaluate function 'count' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - up to four comma-separated fields: * + * (1) number of seconds/values * + * (2) value to compare with (optional) * + * Becomes mandatory for numeric items if 3rd * + * parameter is specified and is not "regexp" * + * or "iregexp". With "band" can take one of * + * 2 forms: * + * - value_to_compare_with/mask * + * - mask * + * (3) comparison operator (optional) * + * (4) time shift (optional) * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_COUNT(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, int limit, + char **error) +{ + int arg1, op = OP_UNKNOWN, numeric_search, nparams, count = 0, i, ret = FAIL; + int seconds = 0, nvalues = 0, time_shift; + char *arg2 = NULL, *arg3_2 = NULL, *arg3 = NULL, buf[ZBX_MAX_UINT64_LEN]; + double arg3_dbl; + zbx_uint64_t arg3_ui64, arg3_2_ui64; + zbx_value_type_t arg1_type; + zbx_vector_ptr_t regexps; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + size_t value_alloc = 0, value_offset = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_vector_ptr_create(®exps); + zbx_history_record_vector_create(&values); + + numeric_search = (ITEM_VALUE_TYPE_UINT64 == item->value_type || ITEM_VALUE_TYPE_FLOAT == item->value_type); + + if (4 < (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (2 <= nparams && SUCCEED != get_function_parameter_str(parameters, 2, &arg2)) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + if (3 <= nparams && SUCCEED != get_function_parameter_str(parameters, 3, &arg3)) + { + *error = zbx_strdup(*error, "invalid third parameter"); + goto out; + } + + ts_end.sec -= time_shift; + + if (NULL == arg2 || '\0' == *arg2) + op = (0 != numeric_search ? OP_EQ : OP_LIKE); + else if (0 == strcmp(arg2, "eq")) + op = OP_EQ; + else if (0 == strcmp(arg2, "ne")) + op = OP_NE; + else if (0 == strcmp(arg2, "gt")) + op = OP_GT; + else if (0 == strcmp(arg2, "ge")) + op = OP_GE; + else if (0 == strcmp(arg2, "lt")) + op = OP_LT; + else if (0 == strcmp(arg2, "le")) + op = OP_LE; + else if (0 == strcmp(arg2, "like")) + op = OP_LIKE; + else if (0 == strcmp(arg2, "regexp")) + op = OP_REGEXP; + else if (0 == strcmp(arg2, "iregexp")) + op = OP_IREGEXP; + else if (0 == strcmp(arg2, "band")) + op = OP_BAND; + + if (OP_UNKNOWN == op) + { + *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for function COUNT", arg2); + goto out; + } + + numeric_search = (0 != numeric_search && OP_REGEXP != op && OP_IREGEXP != op); + + if (0 != numeric_search) + { + if (NULL != arg2 && '\0' != *arg2 && '\0' == *arg3) + { + *error = zbx_strdup(*error, "pattern must be provided along with operator for numeric values"); + goto out; + } + + if (OP_LIKE == op) + { + *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting numeric values", + arg3); + goto out; + } + + if (OP_BAND == op && ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting float values", + arg3); + goto out; + } + + if (OP_BAND == op && NULL != (arg3_2 = strchr(arg3, '/'))) + { + *arg3_2 = '\0'; /* end of the 1st part of the 2nd parameter (number to compare with) */ + arg3_2++; /* start of the 2nd part of the 2nd parameter (mask) */ + } + + if (NULL != arg3 && '\0' != *arg3) + { + if (ITEM_VALUE_TYPE_UINT64 == item->value_type) + { + if (OP_BAND != op) + { + if (SUCCEED != str2uint64(arg3, ZBX_UNIT_SYMBOLS, &arg3_ui64)) + { + *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned" + " value", arg3); + goto out; + } + } + else + { + if (SUCCEED != is_uint64(arg3, &arg3_ui64)) + { + *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned" + " value", arg3); + goto out; + } + + if (NULL != arg3_2) + { + if (SUCCEED != is_uint64(arg3_2, &arg3_2_ui64)) + { + *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric" + " unsigned value", arg3_2); + goto out; + } + } + else + arg3_2_ui64 = arg3_ui64; + } + } + else + { + if (SUCCEED != is_double_suffix(arg3, ZBX_FLAG_DOUBLE_SUFFIX)) + { + *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric float value", + arg3); + goto out; + } + + arg3_dbl = str2double(arg3); + } + } + } + else if (OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op && OP_EQ != op && OP_NE != op) + { + *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting textual values", arg2); + goto out; + } + + if ((OP_REGEXP == op || OP_IREGEXP == op) && '@' == *arg3) + { + DCget_expressions_by_name(®exps, arg3 + 1); + + if (0 == regexps.values_num) + { + *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg3 + 1); + goto out; + } + } + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + /* skip counting values one by one if both pattern and operator are empty or "" is searched in text values */ + if ((NULL != arg3 && '\0' != *arg3) || (NULL != arg2 && '\0' != *arg2 && + OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op)) + { + switch (item->value_type) + { + case ITEM_VALUE_TYPE_UINT64: + if (0 != numeric_search) + { + for (i = 0; i < values.values_num && count < limit; i++) + { + count_one_ui64(&count, op, values.values[i].value.ui64, arg3_ui64, + arg3_2_ui64); + } + } + else + { + for (i = 0; i < values.values_num && FAIL != count && count < limit; i++) + { + zbx_snprintf(buf, sizeof(buf), ZBX_FS_UI64, + values.values[i].value.ui64); + count_one_str(&count, op, buf, arg3, ®exps); + } + } + break; + case ITEM_VALUE_TYPE_FLOAT: + if (0 != numeric_search) + { + for (i = 0; i < values.values_num && count < limit; i++) + count_one_dbl(&count, op, values.values[i].value.dbl, arg3_dbl); + } + else + { + for (i = 0; i < values.values_num && FAIL != count && count < limit; i++) + { + zbx_snprintf(buf, sizeof(buf), ZBX_FS_DBL_EXT(4), + values.values[i].value.dbl); + count_one_str(&count, op, buf, arg3, ®exps); + } + } + break; + case ITEM_VALUE_TYPE_LOG: + for (i = 0; i < values.values_num && FAIL != count && count < limit; i++) + count_one_str(&count, op, values.values[i].value.log->value, arg3, ®exps); + break; + default: + for (i = 0; i < values.values_num && FAIL != count && count < limit; i++) + count_one_str(&count, op, values.values[i].value.str, arg3, ®exps); + } + + if (FAIL == count) + { + *error = zbx_strdup(*error, "invalid regular expression"); + goto out; + } + } + else + { + if ((count = values.values_num) > limit) + count = limit; + } + + zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", count); + + ret = SUCCEED; +out: + zbx_free(arg2); + zbx_free(arg3); + + zbx_regexp_clean_expressions(®exps); + zbx_vector_ptr_destroy(®exps); + + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +#undef OP_UNKNOWN +#undef OP_EQ +#undef OP_NE +#undef OP_GT +#undef OP_GE +#undef OP_LT +#undef OP_LE +#undef OP_LIKE +#undef OP_REGEXP +#undef OP_IREGEXP +#undef OP_BAND +#undef OP_MAX + +/****************************************************************************** + * * + * Function: evaluate_SUM * + * * + * Purpose: evaluate function 'sum' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_SUM(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) +{ + int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + zbx_vector_history_record_t values; + history_value_t result; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 != (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + ts_end.sec -= time_shift; + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + result.dbl = 0; + + for (i = 0; i < values.values_num; i++) + result.dbl += values.values[i].value.dbl; + } + else + { + result.ui64 = 0; + + for (i = 0; i < values.values_num; i++) + result.ui64 += values.values[i].value.ui64; + } + + *value = zbx_history_value2str_dyn(&result, item->value_type); + ret = SUCCEED; +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_AVG * + * * + * Purpose: evaluate function 'avg' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_AVG(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) +{ + int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 != (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + ts_end.sec -= time_shift; + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + double avg = 0; + size_t value_alloc = 0, value_offset = 0; + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + for (i = 0; i < values.values_num; i++) + avg += values.values[i].value.dbl / (i + 1) - avg / (i + 1); + } + else + { + for (i = 0; i < values.values_num; i++) + avg += values.values[i].value.ui64; + + avg = avg / values.values_num; + } + zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, avg); + + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for AVG is empty"); + *error = zbx_strdup(*error, "not enough data"); + } +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_LAST * + * * + * Purpose: evaluate functions 'last' and 'prev' for the item * + * * + * Parameters: value - dynamic buffer * + * item - item (performance metric) * + * parameters - Nth last value and time shift (optional) * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_LAST(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + int arg1 = 1, ret = FAIL, time_shift; + zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift)) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (ZBX_VALUE_NVALUES != arg1_type) + arg1 = 1; /* time or non parameter is defaulted to "last(0)" */ + + ts_end.sec -= time_shift; + + if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, 0, arg1, &ts_end)) + { + if (arg1 <= values.values_num) + { + char *tmp; + + tmp = zbx_history_value2str_dyn(&values.values[arg1 - 1].value, item->value_type); + + if (ITEM_VALUE_TYPE_STR == item->value_type || + ITEM_VALUE_TYPE_TEXT == item->value_type || + ITEM_VALUE_TYPE_LOG == item->value_type) + { + size_t len; + char *ptr; + + len = zbx_get_escape_string_len(tmp, "\"\\"); + ptr = *value = zbx_malloc(NULL, len + 3); + *ptr++ = '"'; + zbx_escape_string(ptr, len + 1, tmp, "\"\\"); + ptr += len; + *ptr++ = '"'; + *ptr = '\0'; + zbx_free(tmp); + } + else + *value = tmp; + + ret = SUCCEED; + } + else + { + *error = zbx_strdup(*error, "not enough data"); + goto out; + } + } + else + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + } +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_MIN * + * * + * Purpose: evaluate function 'min' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_MIN(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) +{ + int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 != (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + ts_end.sec -= time_shift; + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + int index = 0; + + if (ITEM_VALUE_TYPE_UINT64 == item->value_type) + { + for (i = 1; i < values.values_num; i++) + { + if (values.values[i].value.ui64 < values.values[index].value.ui64) + index = i; + } + } + else + { + for (i = 1; i < values.values_num; i++) + { + if (values.values[i].value.dbl < values.values[index].value.dbl) + index = i; + } + } + + *value = zbx_history_value2str_dyn(&values.values[index].value, item->value_type); + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for MIN is empty"); + *error = zbx_strdup(*error, "not enough data"); + } +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_MAX * + * * + * Purpose: evaluate function 'max' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_MAX(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error) +{ + int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 != (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + ts_end.sec -= time_shift; + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + int index = 0; + + if (ITEM_VALUE_TYPE_UINT64 == item->value_type) + { + for (i = 1; i < values.values_num; i++) + { + if (values.values[i].value.ui64 > values.values[index].value.ui64) + index = i; + } + } + else + { + for (i = 1; i < values.values_num; i++) + { + if (values.values[i].value.dbl > values.values[index].value.dbl) + index = i; + } + } + + *value = zbx_history_value2str_dyn(&values.values[index].value, item->value_type); + + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for MAX is empty"); + *error = zbx_strdup(*error, "not enough data"); + } +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static int __history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl); + + return 0; +} + +static int __history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2) +{ + ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64); + + return 0; +} + +/****************************************************************************** + * * + * Function: evaluate_PERCENTILE * + * * + * Purpose: evaluate function 'percentile' for the item * + * * + * Parameters: item - [IN] item (performance metric) * + * parameters - [IN] seconds/values, time shift (optional), * + * percentage * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in * + * 'value' * + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_PERCENTILE(char **value, DC_ITEM *item, const char *parameters, + const zbx_timespec_t *ts, char **error) +{ + int nparams, arg1, time_shift, ret = FAIL, seconds = 0, nvalues = 0; + zbx_value_type_t arg1_type; + double percentage; + zbx_vector_history_record_t values; + zbx_timespec_t ts_end = *ts; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (2 != (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + ts_end.sec -= time_shift; + + if (SUCCEED != get_function_parameter_float(parameters, 2, ZBX_FLAG_DOUBLE_PLAIN, &percentage) || + 0.0 > percentage || 100.0 < percentage) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + int index; + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_float_compare); + else + zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_uint64_compare); + + if (0 == percentage) + index = 1; + else + index = (int)ceil(values.values_num * (percentage / 100)); + + *value = zbx_history_value2str_dyn(&values.values[index - 1].value, item->value_type); + + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "result for PERCENTILE is empty"); + *error = zbx_strdup(*error, "not enough data"); + } +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_NODATA * + * * + * Purpose: evaluate function 'nodata' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_NODATA(char **value, DC_ITEM *item, const char *parameters, char **error) +{ + int arg1, num, period, lazy = 1, ret = FAIL; + zbx_value_type_t arg1_type; + zbx_vector_history_record_t values; + zbx_timespec_t ts; + char *arg2 = NULL; + zbx_proxy_suppress_t nodata_win; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (2 < (num = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || + ZBX_VALUE_SECONDS != arg1_type || 0 >= arg1) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (1 < num && (SUCCEED != get_function_parameter_str(parameters, 2, &arg2) || + ('\0' != *arg2 && 0 != (lazy = strcmp("strict", arg2))))) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + zbx_timespec(&ts); + nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE; + + if (0 != item->host.proxy_hostid && 0 != lazy) + { + int lastaccess; + + if (SUCCEED != DCget_proxy_nodata_win(item->host.proxy_hostid, &nodata_win, &lastaccess)) + { + *error = zbx_strdup(*error, "cannot retrieve proxy last access"); + goto out; + } + + period = arg1 + (ts.sec - lastaccess); + } + else + period = arg1; + + if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, period, 1, &ts) && + 1 == values.values_num) + { + *value = zbx_strdup(*value, "0"); + } + else + { + int seconds; + + if (SUCCEED != DCget_data_expected_from(item->itemid, &seconds)) + { + *error = zbx_strdup(*error, "item does not exist, is disabled or belongs to a disabled host"); + goto out; + } + + if (seconds + arg1 > ts.sec) + { + *error = zbx_strdup(*error, + "item does not have enough data after server start or item creation"); + goto out; + } + + if (0 != (nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE)) + { + *error = zbx_strdup(*error, "historical data transfer from proxy is still in progress"); + goto out; + } + + *value = zbx_strdup(*value, "1"); + + if (0 != item->host.proxy_hostid && 0 != lazy) + { + zabbix_log(LOG_LEVEL_TRACE, "Nodata in %s() flag:%d values_num:%d start_time:%d period:%d", + __func__, nodata_win.flags, nodata_win.values_num, ts.sec - period, period); + } + } + + ret = SUCCEED; +out: + zbx_history_record_vector_destroy(&values, item->value_type); + zbx_free(arg2); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + + +/****************************************************************************** + * * + * Function: evaluate_FUZZYTIME * + * * + * Purpose: evaluate function 'fuzzytime' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_FUZZYTIME(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + int arg1, ret = FAIL; + zbx_value_type_t arg1_type; + zbx_history_record_t vc_value; + zbx_uint64_t fuzlow, fuzhig; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (1 < num_param(parameters)) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (ZBX_VALUE_SECONDS != arg1_type || ts->sec <= arg1) + { + *error = zbx_strdup(*error, "invalid argument type or value"); + goto out; + } + + if (SUCCEED != zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value)) + { + *error = zbx_strdup(*error, "cannot get value from value cache"); + goto out; + } + + fuzlow = (int)(ts->sec - arg1); + fuzhig = (int)(ts->sec + arg1); + + if (ITEM_VALUE_TYPE_UINT64 == item->value_type) + { + if (vc_value.value.ui64 >= fuzlow && vc_value.value.ui64 <= fuzhig) + *value = zbx_strdup(*value, "1"); + else + *value = zbx_strdup(*value, "0"); + } + else + { + if (vc_value.value.dbl >= fuzlow && vc_value.value.dbl <= fuzhig) + *value = zbx_strdup(*value, "1"); + else + *value = zbx_strdup(*value, "0"); + } + + zbx_history_record_clear(&vc_value, item->value_type); + + ret = SUCCEED; +out: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_BAND * + * * + * Purpose: evaluate logical bitwise function 'and' for the item * + * * + * Parameters: value - dynamic buffer * + * item - item (performance metric) * + * parameters - up to 3 comma-separated fields: * + * (1) same as the 1st parameter for function * + * evaluate_LAST() (see documentation of * + * trigger function last()), * + * (2) mask to bitwise AND with (mandatory), * + * (3) same as the 2nd parameter for function * + * evaluate_LAST() (see documentation of * + * trigger function last()). * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_BAND(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + char *last_parameters = NULL; + int nparams, ret = FAIL; + zbx_uint64_t last_uint64, mask; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto clean; + } + + if (2 < (nparams = num_param(parameters))) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto clean; + } + + if (SUCCEED != get_function_parameter_uint64(parameters, 2, &mask)) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto clean; + } + + /* prepare the 1st and the 3rd parameter for passing to evaluate_LAST() */ + last_parameters = zbx_function_get_param_dyn(parameters, 1); + + if (SUCCEED == evaluate_LAST(value, item, last_parameters, ts, error)) + { + ZBX_STR2UINT64(last_uint64, *value); + /* 'and' bit operation cannot be larger than the source value, */ + /* so the result can just be copied in value buffer */ + zbx_snprintf(*value, strlen(*value) + 1, ZBX_FS_UI64, last_uint64 & (zbx_uint64_t)mask); + ret = SUCCEED; + } + + zbx_free(last_parameters); +clean: + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_FORECAST * + * * + * Purpose: evaluate function 'forecast' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_FORECAST(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + char *fit_str = NULL, *mode_str = NULL; + double *t = NULL, *x = NULL; + int nparams, time, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t time_type, arg1_type; + unsigned int k = 0; + zbx_vector_history_record_t values; + zbx_timespec_t zero_time; + zbx_fit_t fit; + zbx_mode_t mode; + zbx_timespec_t ts_end = *ts; + size_t value_alloc = 0, value_offset = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (2 > (nparams = num_param(parameters)) || nparams > 4) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_MANDATORY, &time, &time_type) || + ZBX_VALUE_SECONDS != time_type) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + if (4 <= nparams) + { + if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) || + SUCCEED != zbx_fit_code(fit_str, &fit, &k, error)) + { + *error = zbx_strdup(*error, "invalid third parameter"); + goto out; + } + } + else + { + fit = FIT_LINEAR; + } + + if (4 == nparams) + { + if (SUCCEED != get_function_parameter_str(parameters, 4, &mode_str) || + SUCCEED != zbx_mode_code(mode_str, &mode, error)) + { + *error = zbx_strdup(*error, "invalid fourth parameter"); + goto out; + } + } + else + { + mode = MODE_VALUE; + } + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + ts_end.sec -= time_shift; + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + t = (double *)zbx_malloc(t, values.values_num * sizeof(double)); + x = (double *)zbx_malloc(x, values.values_num * sizeof(double)); + + zero_time.sec = values.values[values.values_num - 1].timestamp.sec; + zero_time.ns = values.values[values.values_num - 1].timestamp.ns; + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + for (i = 0; i < values.values_num; i++) + { + t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 * + (values.values[i].timestamp.ns - zero_time.ns + 1); + x[i] = values.values[i].value.dbl; + } + } + else + { + for (i = 0; i < values.values_num; i++) + { + t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 * + (values.values[i].timestamp.ns - zero_time.ns + 1); + x[i] = values.values[i].value.ui64; + } + } + + zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, zbx_forecast(t, x, + values.values_num, ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), time, fit, k, + mode)); + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "no data available"); + zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, ZBX_MATH_ERROR); + } + + ret = SUCCEED; +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zbx_free(fit_str); + zbx_free(mode_str); + + zbx_free(t); + zbx_free(x); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_TIMELEFT * + * * + * Purpose: evaluate function 'timeleft' for the item * + * * + * Parameters: item - item (performance metric) * + * parameters - number of seconds/values and time shift (optional)* + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_TIMELEFT(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, + char **error) +{ + char *fit_str = NULL; + double *t = NULL, *x = NULL, threshold; + int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift; + zbx_value_type_t arg1_type; + unsigned k = 0; + zbx_vector_history_record_t values; + zbx_timespec_t zero_time; + zbx_fit_t fit; + zbx_timespec_t ts_end = *ts; + size_t value_alloc = 0, value_offset = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_history_record_vector_create(&values); + + if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type) + { + *error = zbx_strdup(*error, "invalid value type"); + goto out; + } + + if (2 > (nparams = num_param(parameters)) || nparams > 3) + { + *error = zbx_strdup(*error, "invalid number of parameters"); + goto out; + } + + if (SUCCEED != get_function_parameter_hist_range(ts->sec, parameters, 1, &arg1, &arg1_type, &time_shift) || + ZBX_VALUE_NONE == arg1_type) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (SUCCEED != get_function_parameter_float( parameters, 2, ZBX_FLAG_DOUBLE_SUFFIX, &threshold)) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + if (4 == nparams) + { + if (SUCCEED != get_function_parameter_str(parameters, 3, &fit_str) || + SUCCEED != zbx_fit_code(fit_str, &fit, &k, error)) + { + *error = zbx_strdup(*error, "invalid third parameter"); + goto out; + } + } + else + { + fit = FIT_LINEAR; + } + + if ((FIT_EXPONENTIAL == fit || FIT_POWER == fit) && 0.0 >= threshold) + { + *error = zbx_strdup(*error, "exponential and power functions are always positive"); + goto out; + } + + switch (arg1_type) + { + case ZBX_VALUE_SECONDS: + seconds = arg1; + break; + case ZBX_VALUE_NVALUES: + nvalues = arg1; + break; + default: + THIS_SHOULD_NEVER_HAPPEN; + } + + ts_end.sec -= time_shift; + + if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end)) + { + *error = zbx_strdup(*error, "cannot get values from value cache"); + goto out; + } + + if (0 < values.values_num) + { + t = (double *)zbx_malloc(t, values.values_num * sizeof(double)); + x = (double *)zbx_malloc(x, values.values_num * sizeof(double)); + + zero_time.sec = values.values[values.values_num - 1].timestamp.sec; + zero_time.ns = values.values[values.values_num - 1].timestamp.ns; + + if (ITEM_VALUE_TYPE_FLOAT == item->value_type) + { + for (i = 0; i < values.values_num; i++) + { + t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 * + (values.values[i].timestamp.ns - zero_time.ns + 1); + x[i] = values.values[i].value.dbl; + } + } + else + { + for (i = 0; i < values.values_num; i++) + { + t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 * + (values.values[i].timestamp.ns - zero_time.ns + 1); + x[i] = values.values[i].value.ui64; + } + } + + zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, zbx_timeleft(t, x, + values.values_num, ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), threshold, + fit, k)); + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "no data available"); + zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, ZBX_MATH_ERROR); + } + + ret = SUCCEED; +out: + zbx_history_record_vector_destroy(&values, item->value_type); + + zbx_free(fit_str); + + zbx_free(t); + zbx_free(x); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_TREND * + * * + * Purpose: evaluate trend* functions for the item * + * * + * Parameters: value - [OUT] the function result * + * item - [IN] item (performance metric) * + * func - [IN] the trend function to evaluate * + * (avg, sum, count, delta, max, min) * + * parameters - [IN] function parameters * + * ts - [IN] the historical time when function must be * + * evaluated * + * * + * Return value: SUCCEED - evaluated successfully, result is stored in 'value'* + * FAIL - failed to evaluate function * + * * + ******************************************************************************/ +static int evaluate_TREND(char **value, DC_ITEM *item, const char *func, const char *parameters, + const zbx_timespec_t *ts, char **error) +{ + int ret = FAIL, start, end; + char *period = NULL, *period_shift = NULL; + const char *table; + double value_dbl; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (SUCCEED != get_function_parameter_str(parameters, 1, &period)) + { + *error = zbx_strdup(*error, "invalid first parameter"); + goto out; + } + + if (SUCCEED != get_function_parameter_str(parameters, 2, &period_shift)) + { + *error = zbx_strdup(*error, "invalid second parameter"); + goto out; + } + + if (SUCCEED != zbx_trends_parse_range(ts->sec, parameters, &start, &end, error)) + goto out; + + switch (item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: + table = "trends"; + break; + case ITEM_VALUE_TYPE_UINT64: + table = "trends_uint"; + break; + default: + *error = zbx_strdup(*error, "unsupported value type"); + goto out; + } + + if (0 == strcmp(func, "avg")) + { + ret = zbx_trends_eval_avg(table, item->itemid, start, end, &value_dbl, error); + } + else if (0 == strcmp(func, "count")) + { + ret = zbx_trends_eval_count(table, item->itemid, start, end, &value_dbl, error); + } + else if (0 == strcmp(func, "delta")) + { + ret = zbx_trends_eval_delta(table, item->itemid, start, end, &value_dbl, error); + } + else if (0 == strcmp(func, "max")) + { + ret = zbx_trends_eval_max(table, item->itemid, start, end, &value_dbl, error); + } + else if (0 == strcmp(func, "min")) + { + ret = zbx_trends_eval_min(table, item->itemid, start, end, &value_dbl, error); + } + else if (0 == strcmp(func, "sum")) + { + ret = zbx_trends_eval_sum(table, item->itemid, start, end, &value_dbl, error); + } + else + { + *error = zbx_strdup(*error, "unknown trend function"); + goto out; + } + + if (SUCCEED == ret) + *value = zbx_dsprintf(*value, ZBX_FS_DBL64, value_dbl); +out: + zbx_free(period); + zbx_free(period_shift); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: evaluate_function * + * * + * Purpose: evaluate function * + * * + * Parameters: item - item to calculate function for * + * function - function (for example, 'max') * + * parameter - parameter of the function * + * * + * Return value: SUCCEED - evaluated successfully, value contains its value * + * FAIL - evaluation failed * + * * + ******************************************************************************/ +int evaluate_function2(char **value, DC_ITEM *item, const char *function, const char *parameter, + const zbx_timespec_t *ts, char **error) +{ + int ret; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:'%s:%s.%s(%s)' ts:'%s\'", __func__, + item->host.host, item->key_orig, function, parameter, zbx_timespec_str(ts)); + + if (0 == strcmp(function, "last")) + { + ret = evaluate_LAST(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "prev")) + { + ret = evaluate_LAST(value, item, "#2", ts, error); + } + else if (0 == strcmp(function, "min")) + { + ret = evaluate_MIN(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "max")) + { + ret = evaluate_MAX(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "avg")) + { + ret = evaluate_AVG(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "sum")) + { + ret = evaluate_SUM(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "percentile")) + { + ret = evaluate_PERCENTILE(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "count")) + { + ret = evaluate_COUNT(value, item, parameter, ts, ZBX_MAX_UINT31_1, error); + } + else if (0 == strcmp(function, "nodata")) + { + ret = evaluate_NODATA(value, item, parameter, error); + } + else if (0 == strcmp(function, "find")) + { + ret = evaluate_COUNT(value, item, parameter, ts, 1, error); + } + else if (0 == strcmp(function, "fuzzytime")) + { + ret = evaluate_FUZZYTIME(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "logeventid")) + { + ret = evaluate_LOGEVENTID(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "logseverity")) + { + ret = evaluate_LOGSEVERITY(value, item, ts, error); + } + else if (0 == strcmp(function, "logsource")) + { + ret = evaluate_LOGSOURCE(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "band")) + { + ret = evaluate_BAND(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "forecast")) + { + ret = evaluate_FORECAST(value, item, parameter, ts, error); + } + else if (0 == strcmp(function, "timeleft")) + { + ret = evaluate_TIMELEFT(value, item, parameter, ts, error); + } + else if (0 == strncmp(function, "trend", 5)) + { + ret = evaluate_TREND(value, item, function + 5, parameter, ts, error); + } + else + { + *error = zbx_strdup(*error, "function is not supported"); + ret = FAIL; + } + + if (SUCCEED == ret) + del_zeros(*value); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:'%s'", __func__, zbx_result_string(ret), ZBX_NULL2STR(*value)); + + return ret; +} diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c index 93ad8c92b22..0d4af94b683 100644 --- a/src/libs/zbxserver/expression.c +++ b/src/libs/zbxserver/expression.c @@ -5128,7 +5128,7 @@ static void zbx_evaluate_item_functions(zbx_hashset_t *funcs) continue; } - if (SUCCEED != evaluate_function(&value, &items[i], func->function, func->parameter, &func->timespec, + if (SUCCEED != evaluate_function2(&value, &items[i], func->function, func->parameter, &func->timespec, &error)) { /* compose and store error message for future use */ diff --git a/src/libs/zbxtrends/trends.c b/src/libs/zbxtrends/trends.c index 3ed8d841898..7e9286f0392 100644 --- a/src/libs/zbxtrends/trends.c +++ b/src/libs/zbxtrends/trends.c @@ -106,76 +106,39 @@ int zbx_trends_parse_base(const char *params, zbx_time_unit_t *base, char **erro /****************************************************************************** * * - * Function: zbx_trends_parse_range * + * Function: trends_parse_timeshift * * * - * Purpose: parse trend function period arguments into time range * + * Purpose: parse timeshift * * * - * Parameters: from - [IN] the time the period shift is calculated * - * from * - * period - [IN] the history period * - * period_shift - [IN] the history period shift * - * start - [OUT] the period start time in seconds since * - * Epoch * - * end - [OUT] the period end time in seconds since * - * Epoch * - * error - [OUT] the error message if parsing failed * + * Parameters: from - [IN] the start time * + * timeshift - [IN] the timeshift string * + * min_time_unit - [IN] minimum time unit that can be used * + * tm - [IN] the shifted time * + * error - [OUT] the error message if parsing failed * * * - * Return value: SUCCEED - period was parsed successfully * - * FAIL - invalid time period was specified * - * * - * Comments: Daylight saving changes are applied when parsing ranges with * - * day+ used as period base (now/?). * - * * - * Example period_shift values: * - * now/d * - * now/d-1h * - * now/d+1h * - * now/d+1h/w * - * now/d/w/h+1h+2h * - * now-1d/h * + * Return value: SUCCEED - time shift was parsed successfully * + * FAIL - otherwise * * * ******************************************************************************/ -int zbx_trends_parse_range(time_t from, const char *period, const char *period_shift, int *start, int *end, +static int trends_parse_timeshift(time_t from, const char *timeshift, zbx_time_unit_t min_time_unit, struct tm *tm, char **error) { - int period_num, period_hours[ZBX_TIME_UNIT_COUNT] = {0, 1, 24, 24 * 7, 24 * 30, 24 * 365}; - zbx_time_unit_t period_unit; size_t len; - struct tm tm_end, tm_start; const char *p; - zabbix_log(LOG_LEVEL_DEBUG, "In %s() period:%s shift:%s", __func__, period, period_shift); + zabbix_log(LOG_LEVEL_DEBUG, "In %s() shift:%s", __func__, timeshift); - /* parse period */ - - if (SUCCEED != zbx_tm_parse_period(period, &len, &period_num, &period_unit, error)) - return FAIL; - - if ('\0' != period[len]) - { - *error = zbx_dsprintf(*error, "unexpected character[s] in period \"%s\"", period + len); - return FAIL; - } - - if (period_hours[period_unit] * period_num > 24 * 366) - { - *error = zbx_strdup(*error, "period is too large"); - return FAIL; - } - - /* parse period shift */ - - p = period_shift; + p = timeshift; if (0 != strncmp(p, "now", ZBX_CONST_STRLEN("now"))) { - *error = zbx_strdup(*error, "period shift must begin with \"now\""); + *error = zbx_strdup(*error, "time shift must begin with \"now\""); return FAIL; } p += ZBX_CONST_STRLEN("now"); - localtime_r(&from, &tm_end); + localtime_r(&from, tm); while ('\0' != *p) { @@ -189,14 +152,14 @@ int zbx_trends_parse_range(time_t from, const char *period, const char *period_s return FAIL; } - if (unit < period_unit) + if (unit < min_time_unit) { - *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal" + *error = zbx_dsprintf(*error, "time units in time shift must be greater or equal" " to period time unit"); return FAIL; } - zbx_tm_round_down(&tm_end, unit); + zbx_tm_round_down(tm, unit); /* unit is single character */ p++; @@ -209,7 +172,7 @@ int zbx_trends_parse_range(time_t from, const char *period, const char *period_s if (FAIL == zbx_tm_parse_period(p, &len, &num, &unit, error)) return FAIL; - if (unit < period_unit) + if (unit < min_time_unit) { *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal" " to period time unit"); @@ -217,9 +180,9 @@ int zbx_trends_parse_range(time_t from, const char *period, const char *period_s } if ('+' == op) - zbx_tm_add(&tm_end, num, unit); + zbx_tm_add(tm, num, unit); else - zbx_tm_sub(&tm_end, num, unit); + zbx_tm_sub(tm, num, unit); p += len; } @@ -230,6 +193,94 @@ int zbx_trends_parse_range(time_t from, const char *period, const char *period_s } } + zabbix_log(LOG_LEVEL_DEBUG, "End of %s() %04d.%02d.%02d %02d:%02d:%02d", __func__, tm->tm_year + 1900, + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_parse_timeshift * + * * + * Purpose: parse timeshift * + * * + * Parameters: from - [IN] the start time * + * timeshift - [IN] the timeshift string * + * tm - [IN] the shifted time * + * error - [OUT] the error message if parsing failed * + * * + * Return value: SUCCEED - time shift was parsed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_parse_timeshift(time_t from, const char *timeshift, struct tm *tm, char **error) +{ + return trends_parse_timeshift(from, timeshift, ZBX_TIME_UNIT_UNKNOWN, tm, error); +} + +/****************************************************************************** + * * + * Function: zbx_trends_parse_range * + * * + * Purpose: parse trend function period arguments into time range * + * * + * Parameters: from - [IN] the time the period shift is calculated * + * from * + * period - [IN] the history period * + * period_shift - [IN] the history period shift * + * start - [OUT] the period start time in seconds since * + * Epoch * + * end - [OUT] the period end time in seconds since * + * Epoch * + * error - [OUT] the error message if parsing failed * + * * + * Return value: SUCCEED - period was parsed successfully * + * FAIL - invalid time period was specified * + * * + * Comments: Daylight saving changes are applied when parsing ranges with * + * day+ used as period base (now/?). * + * * + * Example period_shift values: * + * now/d * + * now/d-1h * + * now/d+1h * + * now/d+1h/w * + * now/d/w/h+1h+2h * + * now-1d/h * + * * + ******************************************************************************/ +int zbx_trends_parse_range(time_t from, const char *param, int *start, int *end, char **error) +{ + int period_num, period_hours[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, 1, 24, 24 * 7, 24 * 30, 24 * 365}; + zbx_time_unit_t period_unit; + size_t len; + struct tm tm_end, tm_start; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() param:%s", __func__, param); + + /* parse period */ + + if (SUCCEED != zbx_tm_parse_period(param, &len, &period_num, &period_unit, error)) + return FAIL; + + if ('\0' != param[len] && ':' != param[len]) + { + *error = zbx_dsprintf(*error, "unexpected character[s] in period \"%s\"", param + len); + return FAIL; + } + + if (period_hours[period_unit] * period_num > 24 * 366) + { + *error = zbx_strdup(*error, "period is too large"); + return FAIL; + } + + /* parse period shift */ + + if (SUCCEED != trends_parse_timeshift(from, param + len + 1, period_unit, &tm_end, error)) + return FAIL; + tm_start = tm_end; /* trends clock refers to the beginning of the hourly interval - subtract */ @@ -285,7 +336,7 @@ int zbx_trends_parse_nextcheck(time_t from, const char *period_shift, time_t *ne struct tm tm; zbx_time_unit_t base; - if (SUCCEED != trends_parse_base(period_shift, &base, error)) + if (SUCCEED != trends_parse_base(period_shift, &base, error) || ZBX_TIME_UNIT_HOUR > base) return FAIL; /* parse period shift */ diff --git a/tests/libs/zbxcommon/zbx_tm_add.yaml b/tests/libs/zbxcommon/zbx_tm_add.yaml index 4c6c00d8db5..5e04bbea7ec 100644 --- a/tests/libs/zbxcommon/zbx_tm_add.yaml +++ b/tests/libs/zbxcommon/zbx_tm_add.yaml @@ -166,5 +166,53 @@ in: param: 1d out: time: 2020-01-30 00:00:00 +00:00 +--- +test case: 2020-09-01 00:00:00 +03:00 + 1m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:00 +03:00 + param: 1m +out: + time: 2020-09-01 00:01:00 +03:00 +--- +test case: 2020-09-01 00:59:00 +03:00 + 1m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:59:00 +03:00 + param: 1m +out: + time: 2020-09-01 01:00:00 +03:00 +--- +test case: 2020-03-29 02:59:00 +02:00 + 1m +in: + timezone: :Europe/Riga + time: 2020-03-29 02:59:00 +02:00 + param: 1m +out: + time: 2020-03-29 03:00:00 +03:00 +--- +test case: 2020-09-01 00:00:00 +03:00 + 1s +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:00 +03:00 + param: 1s +out: + time: 2020-09-01 00:00:01 +03:00 +--- +test case: 2020-09-01 00:00:59 +03:00 + 1s +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:59 +03:00 + param: 1s +out: + time: 2020-09-01 00:01:00 +03:00 +--- +test case: 2020-03-29 02:59:59 +02:00 + 1s +in: + timezone: :Europe/Riga + time: 2020-03-29 02:59:59 +02:00 + param: 1s +out: + time: 2020-03-29 03:00:00 +03:00 ... diff --git a/tests/libs/zbxcommon/zbx_tm_round_down.yaml b/tests/libs/zbxcommon/zbx_tm_round_down.yaml index 0ff6b745081..0f4f3e9871f 100644 --- a/tests/libs/zbxcommon/zbx_tm_round_down.yaml +++ b/tests/libs/zbxcommon/zbx_tm_round_down.yaml @@ -94,5 +94,21 @@ in: base: w out: time: 2020-09-07 00:00:00 +03:00 +--- +test case: 2020-09-01 00:00:00 +03:00 / m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:00 +03:00 + base: m +out: + time: 2020-09-01 00:00:00 +03:00 +--- +test case: 2020-09-01 00:01:01 +03:00 / m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:01:01 +03:00 + base: m +out: + time: 2020-09-01 00:01:00 +03:00 ... diff --git a/tests/libs/zbxcommon/zbx_tm_round_up.yaml b/tests/libs/zbxcommon/zbx_tm_round_up.yaml index fb803b6c52d..463bfe62617 100644 --- a/tests/libs/zbxcommon/zbx_tm_round_up.yaml +++ b/tests/libs/zbxcommon/zbx_tm_round_up.yaml @@ -70,5 +70,21 @@ in: base: y out: time: 2021-01-01 00:00:00 +02:00 +--- +test case: 2020-09-01 00:00:00 +03:00 / m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:00 +03:00 + base: m +out: + time: 2020-09-01 00:00:00 +03:00 +--- +test case: 2020-09-01 00:00:01 +03:00 / m +in: + timezone: :Europe/Riga + time: 2020-09-01 00:00:01 +03:00 + base: m +out: + time: 2020-09-01 00:01:00 +03:00 ... diff --git a/tests/libs/zbxcommon/zbx_tm_sub.yaml b/tests/libs/zbxcommon/zbx_tm_sub.yaml index cee97408550..d9bb0fbccfe 100644 --- a/tests/libs/zbxcommon/zbx_tm_sub.yaml +++ b/tests/libs/zbxcommon/zbx_tm_sub.yaml @@ -174,4 +174,36 @@ in: param: 1h out: time: 2019-12-31 23:00:00 +02:00 +--- +test case: 2020-09-01 12:00:00 +03:00 - 1m +in: + timezone: :Europe/Riga + time: 2020-09-01 12:00:00 +03:00 + param: 1m +out: + time: 2020-09-01 11:59:00 +03:00 +--- +test case: 2020-10-25 03:00:00 +02:00 - 1m +in: + timezone: :Europe/Riga + time: 2020-10-25 03:00:00 +02:00 + param: 1m +out: + time: 2020-10-25 02:59:00 +03:00 +--- +test case: 2020-09-01 12:00:00 +03:00 - 1s +in: + timezone: :Europe/Riga + time: 2020-09-01 12:00:00 +03:00 + param: 1s +out: + time: 2020-09-01 11:59:59 +03:00 +--- +test case: 2020-10-25 03:00:00 +02:00 - 1s +in: + timezone: :Europe/Riga + time: 2020-10-25 03:00:00 +02:00 + param: 1s +out: + time: 2020-10-25 02:59:59 +03:00 ... diff --git a/tests/libs/zbxserver/evaluate_function.c b/tests/libs/zbxserver/evaluate_function.c index 0ae935bf135..dc4e30870bf 100644 --- a/tests/libs/zbxserver/evaluate_function.c +++ b/tests/libs/zbxserver/evaluate_function.c @@ -97,7 +97,7 @@ void zbx_mock_test_entry(void **state) zbx_vcmock_set_time(handle, "time"); ts = zbx_vcmock_get_ts(); - if (SUCCEED != (returned_ret = evaluate_function(&returned_value, &item, function, params, &ts, &error))) + if (SUCCEED != (returned_ret = evaluate_function2(&returned_value, &item, function, params, &ts, &error))) printf("evaluate_function returned error: %s\n", error); expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return")); @@ -122,5 +122,7 @@ void zbx_mock_test_entry(void **state) } zbx_free(returned_value); + zbx_vcmock_ds_destroy(); + ZBX_UNUSED(state); } diff --git a/tests/libs/zbxserver/evaluate_function.yaml b/tests/libs/zbxserver/evaluate_function.yaml index aa6ce9db17f..ca67c24eaa1 100644 --- a/tests/libs/zbxserver/evaluate_function.yaml +++ b/tests/libs/zbxserver/evaluate_function.yaml @@ -16,7 +16,7 @@ out: return: SUCCEED value: 0.2 --- -test case: Evaluate last(#2) <- 0.1, 0.2 +test case: Evaluate last(2) <- 0.1, 0.2 in: history: - itemid: 1 @@ -28,7 +28,7 @@ in: ts: 2017-01-10 10:00:30.000000000 +00:00 time: 2017-01-10 10:10:00.000000000 +00:00 function: last - params: '#2' + params: '2' out: return: SUCCEED value: 0.1 @@ -114,7 +114,7 @@ out: return: SUCCEED value: '"\"c:\\\""' --- -test case: Evaluate abschange() <- 0.1, 0.2 +test case: Evaluate last(:now-10m) <- 0.1, 0.2 in: history: - itemid: 1 @@ -125,114 +125,13 @@ in: - value: 0.2 ts: 2017-01-10 10:00:30.000000000 +00:00 time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' + function: last + params: :now-10m out: return: SUCCEED value: 0.1 --- -test case: Evaluate abschange() <- 10, 7 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 10 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 7 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' -out: - return: SUCCEED - value: 3 ---- -test case: Evaluate abschange() <- 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_STR - data: - - value: a - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate abschange() <- 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_TEXT - data: - - value: x - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate abschange() <- @log 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: a - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate abschange() <- @log 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: x - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: abschange - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate avg(#2) +test case: Evaluate avg(2) in: history: - itemid: 1 @@ -250,7 +149,7 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: avg - params: '#2' + params: 2 out: return: SUCCEED value: 4.5 @@ -273,12 +172,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: avg - params: '3m' + params: 3m out: return: SUCCEED value: 4 --- -test case: Evaluate avg(#2,1m) +test case: Evaluate avg(2:now-1m) in: history: - itemid: 1 @@ -296,12 +195,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: avg - params: '#2,1m' + params: 2:now-1m out: return: SUCCEED value: 3.5 --- -test case: Evaluate band(#1,1) +test case: Evaluate band(1,1) in: history: - itemid: 1 @@ -319,12 +218,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: band - params: '#1,1' + params: '1,1' out: return: SUCCEED value: 1 --- -test case: Evaluate band(#2,1) +test case: Evaluate band(2,1) in: history: - itemid: 1 @@ -342,12 +241,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: band - params: '#2,1' + params: '2,1' out: return: SUCCEED value: 0 --- -test case: Evaluate band(2m,2,1m) +test case: Evaluate band(2:now-1m,2) in: history: - itemid: 1 @@ -365,130 +264,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: band - params: '#2,2,1m' + params: '2:now-1m,2' out: return: SUCCEED value: 2 --- -test case: Evaluate change() <- 0.1, 0.2 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_FLOAT - data: - - value: 0.1 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 0.2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: 0.1 ---- -test case: Evaluate change() <- 10, 7 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 10 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 7 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: -3 ---- -test case: Evaluate change() <- 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_STR - data: - - value: a - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate change() <- 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_TEXT - data: - - value: x - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate change() <- @log 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: a - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate change() <- @log 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: x - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: change - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate count(#3,4,ge) +test case: Evaluate count(3,ge,4) in: history: - itemid: 1 @@ -506,12 +287,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '#3,4,ge' + params: '3,ge,4' out: return: SUCCEED value: 2 --- -test case: Evaluate count(#3,o,like) +test case: Evaluate count(5m,like,"o") in: history: - itemid: 1 @@ -529,12 +310,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '5m,"o",like' + params: '5m,like,"o"' out: return: SUCCEED value: 2 --- -test case: Evaluate count(#3,o$,regexp) +test case: Evaluate count(5m,regexp,"o$") in: history: - itemid: 1 @@ -552,12 +333,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '5m,"o$",regexp' + params: '5m,regexp,"o$"' out: return: SUCCEED value: 1 --- -test case: Evaluate count(#3,o,iregexp) +test case: Evaluate count(5m,iregexp,"o") in: history: - itemid: 1 @@ -575,12 +356,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '5m,"o",iregexp' + params: '5m,iregexp,"o"' out: return: SUCCEED value: 3 --- -test case: Evaluate count(#3,1/3,band) +test case: Evaluate count(3,band,1/3) in: history: - itemid: 1 @@ -598,12 +379,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '5m,1/3,band' + params: '5m,band,1/3' out: return: SUCCEED value: 2 --- -test case: Evaluate count(#3,2/3,band) +test case: Evaluate count(5m,band,"2/3") in: history: - itemid: 1 @@ -621,270 +402,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: count - params: '5m,2/3,band' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate date() -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1 - ts: 2017-01-10 10:01:00.000000000 +00:00 - time: 2017-12-23 12:34:56.000000000 +00:00 - function: date - params: '' -out: - return: SUCCEED - value: 20171223 ---- -test case: Evaluate dayofmonth() -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1 - ts: 2017-01-10 10:01:00.000000000 +00:00 - time: 2017-12-23 12:34:53.000000000 +00:00 - function: dayofmonth - params: '' -out: - return: SUCCEED - value: 23 ---- -test case: Evaluate dayofweek() -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1 - ts: 2017-01-10 10:01:00.000000000 +00:00 - time: 2020-03-17 12:34:53.000000000 +00:00 - function: dayofweek - params: '' -out: - return: SUCCEED - value: 2 ---- -test case: Evaluate time() -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1 - ts: 2017-01-10 10:01:00.000000000 +00:00 - time: 2017-12-23 12:34:56.000000000 +00:00 - function: time - params: '' -out: - return: SUCCEED - value: 123456 ---- -test case: Evaluate delta(#4) -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 0 - ts: 2017-01-10 10:01:00.000000000 +00:00 - - value: 2 - ts: 2017-01-10 10:02:00.000000000 +00:00 - - value: 3 - ts: 2017-01-10 10:03:00.000000000 +00:00 - - value: 4 - ts: 2017-01-10 10:04:00.000000000 +00:00 - - value: 5 - ts: 2017-01-10 10:05:00.000000000 +00:00 - time: 2017-01-10 10:05:00.000000000 +00:00 - function: delta - params: '#4' -out: - return: SUCCEED - value: 3 ---- -test case: Evaluate delta(4m,1m) -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 0 - ts: 2017-01-10 10:01:00.000000000 +00:00 - - value: 2 - ts: 2017-01-10 10:02:00.000000000 +00:00 - - value: 3 - ts: 2017-01-10 10:03:00.000000000 +00:00 - - value: 4 - ts: 2017-01-10 10:04:00.000000000 +00:00 - - value: 5 - ts: 2017-01-10 10:05:00.000000000 +00:00 - time: 2017-01-10 10:05:00.000000000 +00:00 - function: delta - params: '4m,1m' -out: - return: SUCCEED - value: 4 ---- -test case: Evaluate diff() <- 0.1, 0.2 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_FLOAT - data: - - value: 0.1 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 0.2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate diff() <- 0.123, 0.123 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_FLOAT - data: - - value: 0.123 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 0.123 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate diff() <- 10, 7 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 10 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 7 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate diff() <- 1234567890, 1234567890 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1234567890 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 1234567890 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate diff() <- 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_STR - data: - - value: a - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate diff() <- 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_TEXT - data: - - value: x - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate diff() <- @log 'a', 'b' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: a - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: b - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' + params: '5m,band,2/3' out: return: SUCCEED value: 1 --- -test case: Evaluate diff() <- @log 'x', 'x' -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: x - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: x - source: - logeventid: 2 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: diff - params: '' -out: - return: SUCCEED - value: 0 ---- -test case: Evaluate forecast(#5,,1h) +test case: Evaluate forecast(5,1h) in: history: - itemid: 1 @@ -902,12 +425,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: forecast - params: '#5,,1h' + params: '5,1h' out: return: SUCCEED value: 65 --- -test case: Evaluate forecast(#5,1h,1h) +test case: Evaluate forecast(5:now-1h,1h) in: history: - itemid: 1 @@ -925,12 +448,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: forecast - params: '#5,1h,1h' + params: '5:now-1h,1h' out: return: SUCCEED value: -1 --- -test case: Evaluate fuzzytime(1) < @uint64 +test case: Evaluate fuzzytime(1s) < @uint64 in: history: - itemid: 1 @@ -940,12 +463,12 @@ in: ts: 2017-01-10 10:01:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: fuzzytime - params: '1' + params: '1s' out: return: SUCCEED value: 0 --- -test case: Evaluate fuzzytime(1) < @float +test case: Evaluate fuzzytime(1s) < @float in: history: - itemid: 1 @@ -955,12 +478,12 @@ in: ts: 2017-01-10 10:01:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: fuzzytime - params: '1' + params: '1s' out: return: SUCCEED value: 0 --- -test case: Evaluate iregexp(^o,#5) +test case: Evaluate find(5,"iregexp","^o") in: history: - itemid: 1 @@ -971,13 +494,13 @@ in: - value: Two ts: 2017-01-10 10:02:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: iregexp - params: '^o,#5' + function: find + params: '5,"iregexp","^o"' out: return: SUCCEED value: 1 --- -test case: Evaluate regexp(^o,#5) +test case: Evaluate find(5,"regexp","^o") in: history: - itemid: 1 @@ -988,13 +511,13 @@ in: - value: Two ts: 2017-01-10 10:02:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: regexp - params: '^o,#5' + function: find + params: '5,"regexp","^o"' out: return: SUCCEED value: 0 --- -test case: Evaluate str(o,#5) +test case: Evaluate find(5,"like","o") in: history: - itemid: 1 @@ -1005,13 +528,13 @@ in: - value: Two ts: 2017-01-10 10:02:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: str - params: 'o,#5' + function: find + params: '5,"like","o"' out: return: SUCCEED value: 1 --- -test case: Evaluate logeventid(^12) +test case: Evaluate logeventid("^12") in: history: - itemid: 1 @@ -1025,12 +548,12 @@ in: ts: 2017-01-10 10:00:00.000000000 +00:00 time: 2017-01-10 10:10:00.000000000 +00:00 function: logeventid - params: '^12' + params: '"^12"' out: return: SUCCEED value: 1 --- -test case: Evaluate logeventid(^34) +test case: Evaluate logeventid("^34") in: history: - itemid: 1 @@ -1044,7 +567,7 @@ in: ts: 2017-01-10 10:00:00.000000000 +00:00 time: 2017-01-10 10:10:00.000000000 +00:00 function: logeventid - params: '^34' + params: '"^34"' out: return: SUCCEED value: 0 @@ -1068,7 +591,7 @@ out: return: SUCCEED value: 4 --- -test case: Evaluate logsource('(Application|System)') <- Application +test case: Evaluate logsource("(Application|System)") <- Application in: history: - itemid: 1 @@ -1147,7 +670,7 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: max - params: '5m,2m' + params: '5m:now-2m' out: return: SUCCEED value: 3 @@ -1193,7 +716,7 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: min - params: '4m,2m' + params: '4m:now-2m' out: return: SUCCEED value: 1 @@ -1228,22 +751,7 @@ out: return: SUCCEED value: 0 --- -test case: Evaluate now() -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_UINT64 - data: - - value: 1 - ts: 2017-01-10 10:01:00.000000000 +00:00 - time: 2017-01-10 10:05:00.000000000 +00:00 - function: now - params: '' -out: - return: SUCCEED - value: 1484042700 ---- -test case: Evaluate percentile(5m,,100) +test case: Evaluate percentile(5m,100) in: history: - itemid: 1 @@ -1261,12 +769,12 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: percentile - params: '5m,,100' + params: '5m,100' out: return: SUCCEED value: 5 --- -test case: Evaluate percentile(5m,,50) +test case: Evaluate percentile(5m,50) in: history: - itemid: 1 @@ -1284,132 +792,89 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: percentile - params: '5m,,50' + params: '5m,50' out: return: SUCCEED value: 3 --- -test case: Evaluate prev() <- 0.1, 0.2 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_FLOAT - data: - - value: 0.1 - ts: 2017-01-10 10:00:00.000000000 +00:00 - - value: 0.2 - ts: 2017-01-10 10:00:30.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: prev - params: '' -out: - return: SUCCEED - value: 0.1 ---- -test case: Evaluate strlen() +test case: Evaluate sum(4) in: history: - itemid: 1 - value type: ITEM_VALUE_TYPE_STR + value type: ITEM_VALUE_TYPE_UINT64 data: - - value: One + - value: 1 ts: 2017-01-10 10:01:00.000000000 +00:00 - - value: Two + - value: 2 ts: 2017-01-10 10:02:00.000000000 +00:00 - - value: Three + - value: 3 ts: 2017-01-10 10:03:00.000000000 +00:00 - - value: Four + - value: 4 ts: 2017-01-10 10:04:00.000000000 +00:00 - - value: Five + - value: 5 ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: strlen - params: '' + function: sum + params: '4' out: return: SUCCEED - value: 4 + value: 14 --- -test case: Evaluate strlen(1m) +test case: Evaluate sum(4m:now-1m) in: history: - itemid: 1 - value type: ITEM_VALUE_TYPE_STR + value type: ITEM_VALUE_TYPE_UINT64 data: - - value: One + - value: 1 ts: 2017-01-10 10:01:00.000000000 +00:00 - - value: Two + - value: 2 ts: 2017-01-10 10:02:00.000000000 +00:00 - - value: Three + - value: 3 ts: 2017-01-10 10:03:00.000000000 +00:00 - - value: Four + - value: 4 ts: 2017-01-10 10:04:00.000000000 +00:00 - - value: Five + - value: 5 ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: strlen - params: '1m' + function: sum + params: '4m:now-1m' out: return: SUCCEED - value: 4 + value: 10 --- -test case: Evaluate strlen(,2m) +test case: Evaluate sum(2m) in: history: - itemid: 1 - value type: ITEM_VALUE_TYPE_STR + value type: ITEM_VALUE_TYPE_UINT64 data: - - value: One + - value: 1 ts: 2017-01-10 10:01:00.000000000 +00:00 - - value: Two + - value: 2 + ts: 2017-01-10 10:01:30.000000000 +00:00 + - value: 3 ts: 2017-01-10 10:02:00.000000000 +00:00 - - value: Three + - value: 4 + ts: 2017-01-10 10:02:30.000000000 +00:00 + - value: 5 ts: 2017-01-10 10:03:00.000000000 +00:00 - - value: Four + - value: 6 + ts: 2017-01-10 10:03:30.000000000 +00:00 + - value: 7 ts: 2017-01-10 10:04:00.000000000 +00:00 - - value: Five - ts: 2017-01-10 10:05:00.000000000 +00:00 - time: 2017-01-10 10:05:00.000000000 +00:00 - function: strlen - params: ',2m' -out: - return: SUCCEED - value: 5 ---- -test case: Evaluate strlen() <- 😓 -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_STR - data: - - value: 😓 + - value: 8 + ts: 2017-01-10 10:04:30.000000000 +00:00 + - value: 9 ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 - function: strlen - params: '' -out: - return: SUCCEED - value: 1 ---- -test case: Evaluate strlen() <- @log -in: - history: - - itemid: 1 - value type: ITEM_VALUE_TYPE_LOG - data: - - value: xyz - source: - logeventid: 1 - severity: 1 - timestamp: 2 - ts: 2017-01-10 10:00:00.000000000 +00:00 - time: 2017-01-10 10:10:00.000000000 +00:00 - function: strlen - params: '' + function: sum + params: '2m' out: return: SUCCEED - value: 3 + value: 30 --- -test case: Evaluate sum(#4) +test case: Evaluate sum(2) in: history: - itemid: 1 @@ -1418,21 +883,29 @@ in: - value: 1 ts: 2017-01-10 10:01:00.000000000 +00:00 - value: 2 - ts: 2017-01-10 10:02:00.000000000 +00:00 + ts: 2017-01-10 10:01:30.000000000 +00:00 - value: 3 - ts: 2017-01-10 10:03:00.000000000 +00:00 + ts: 2017-01-10 10:02:00.000000000 +00:00 - value: 4 - ts: 2017-01-10 10:04:00.000000000 +00:00 + ts: 2017-01-10 10:02:30.000000000 +00:00 - value: 5 + ts: 2017-01-10 10:03:00.000000000 +00:00 + - value: 6 + ts: 2017-01-10 10:03:30.000000000 +00:00 + - value: 7 + ts: 2017-01-10 10:04:00.000000000 +00:00 + - value: 8 + ts: 2017-01-10 10:04:30.000000000 +00:00 + - value: 9 ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: sum - params: '#4' + params: '2' out: return: SUCCEED - value: 14 + value: 17 --- -test case: Evaluate sum(4m,1m) +test case: Evaluate sum(2m:now-1m) in: history: - itemid: 1 @@ -1441,36 +914,60 @@ in: - value: 1 ts: 2017-01-10 10:01:00.000000000 +00:00 - value: 2 - ts: 2017-01-10 10:02:00.000000000 +00:00 + ts: 2017-01-10 10:01:30.000000000 +00:00 - value: 3 - ts: 2017-01-10 10:03:00.000000000 +00:00 + ts: 2017-01-10 10:02:00.000000000 +00:00 - value: 4 - ts: 2017-01-10 10:04:00.000000000 +00:00 + ts: 2017-01-10 10:02:30.000000000 +00:00 - value: 5 + ts: 2017-01-10 10:03:00.000000000 +00:00 + - value: 6 + ts: 2017-01-10 10:03:30.000000000 +00:00 + - value: 7 + ts: 2017-01-10 10:04:00.000000000 +00:00 + - value: 8 + ts: 2017-01-10 10:04:30.000000000 +00:00 + - value: 9 ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: sum - params: '4m,1m' + params: '2m:now-1m' out: return: SUCCEED - value: 10 + value: 22 --- -test case: Evaluate time() +test case: Evaluate sum(2:now-1m) in: history: - itemid: 1 value type: ITEM_VALUE_TYPE_UINT64 data: - value: 1 - ts: 2017-01-10 10:00:00.000000000 +00:00 - time: 2017-12-23 12:34:56.000000000 +00:00 - function: time - params: '' + ts: 2017-01-10 10:01:00.000000000 +00:00 + - value: 2 + ts: 2017-01-10 10:01:30.000000000 +00:00 + - value: 3 + ts: 2017-01-10 10:02:00.000000000 +00:00 + - value: 4 + ts: 2017-01-10 10:02:30.000000000 +00:00 + - value: 5 + ts: 2017-01-10 10:03:00.000000000 +00:00 + - value: 6 + ts: 2017-01-10 10:03:30.000000000 +00:00 + - value: 7 + ts: 2017-01-10 10:04:00.000000000 +00:00 + - value: 8 + ts: 2017-01-10 10:04:30.000000000 +00:00 + - value: 9 + ts: 2017-01-10 10:05:00.000000000 +00:00 + time: 2017-01-10 10:05:00.000000000 +00:00 + function: sum + params: '2:now-1m' out: return: SUCCEED - value: 123456 + value: 13 --- -test case: Evaluate timeleft(5m,,65) +test case: Evaluate timeleft(5m,65) in: history: - itemid: 1 @@ -1488,7 +985,7 @@ in: ts: 2017-01-10 10:05:00.000000000 +00:00 time: 2017-01-10 10:05:00.000000000 +00:00 function: timeleft - params: '5m,,65' + params: '5m,65' out: return: SUCCEED value: 3600 diff --git a/tests/libs/zbxtrends/zbx_trends_parse_range.c b/tests/libs/zbxtrends/zbx_trends_parse_range.c index 7a2eea47f95..f1d6c1fea55 100644 --- a/tests/libs/zbxtrends/zbx_trends_parse_range.c +++ b/tests/libs/zbxtrends/zbx_trends_parse_range.c @@ -51,7 +51,7 @@ DB_RESULT __wrap_DBselect(const char *fmt, ...) void zbx_mock_test_entry(void **state) { - const char *period, *shift; + const char *param; int expected_ret, returned_ret, start, end; char *error = NULL; zbx_timespec_t ts_from, ts_start, ts_end, ts; @@ -66,11 +66,10 @@ void zbx_mock_test_entry(void **state) if (ZBX_MOCK_SUCCESS != zbx_strtime_to_timespec(zbx_mock_get_parameter_string("in.time"), &ts_from)) fail_msg("Invalid input time format"); - period = zbx_mock_get_parameter_string("in.period"); - shift = zbx_mock_get_parameter_string("in.shift"); + param = zbx_mock_get_parameter_string("in.param"); expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return")); - returned_ret = zbx_trends_parse_range(ts_from.sec, period, shift, &start, &end, &error); + returned_ret = zbx_trends_parse_range(ts_from.sec, param, &start, &end, &error); if (FAIL == returned_ret) { diff --git a/tests/libs/zbxtrends/zbx_trends_parse_range.yaml b/tests/libs/zbxtrends/zbx_trends_parse_range.yaml index 2f2202322fb..aabcd17d562 100644 --- a/tests/libs/zbxtrends/zbx_trends_parse_range.yaml +++ b/tests/libs/zbxtrends/zbx_trends_parse_range.yaml @@ -1,8 +1,7 @@ --- test case: Invalid period '' in: - period: - shift: now/h + param: :now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -10,8 +9,7 @@ out: --- test case: Invalid period 'h' in: - period: h - shift: now/h + param: h:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -19,8 +17,7 @@ out: --- test case: Invalid period '1' in: - period: 1 - shift: now/h + param: 1:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -28,8 +25,7 @@ out: --- test case: Invalid period '1H' in: - period: 1H - shift: now/h + param: 1H:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -37,8 +33,7 @@ out: --- test case: Invalid period '0h' in: - period: 0h - shift: now/h + param: 0h:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -46,8 +41,7 @@ out: --- test case: Invalid period '12345678901234567890h' in: - period: 12345678901234567890h - shift: now/h + param: 12345678901234567890h:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -55,8 +49,7 @@ out: --- test case: Valid period '1h' in: - period: 1h - shift: now/h + param: 1h:now/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -66,8 +59,7 @@ out: --- test case: Invalid period shift '/h' in: - period: 1h - shift: /h + param: 1h:/h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -75,8 +67,7 @@ out: --- test case: Invalid period shift 'now-1' in: - period: 1h - shift: now-1 + param: 1h:now-1 timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -84,8 +75,7 @@ out: --- test case: Invalid period shift 'now/h - 1' in: - period: 1h - shift: now/h - 1 + param: 1h:now/h - 1 timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -93,8 +83,7 @@ out: --- test case: Invalid period shift 'now/h-1' in: - period: 1h - shift: now/h-1 + param: 1h:now/h-1 timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -102,8 +91,7 @@ out: --- test case: Invalid period shift 'now/h - 1h' in: - period: 1h - shift: now/h - 1h + param: 1h:now/h - 1h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -111,8 +99,7 @@ out: --- test case: Invalid period shift 'now/m-1m' in: - period: 1h - shift: now/m-1m + param: 1h:now/m-1m timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -120,8 +107,7 @@ out: --- test case: Valid parameters '1h,now/h-1h' in: - period: 1h - shift: now/h-1h + param: 1h:now/h-1h timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -131,8 +117,7 @@ out: --- test case: Valid parameters '1h,now/d' in: - period: 1h - shift: now/d + param: 1h:now/d timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -142,8 +127,7 @@ out: --- test case: Valid parameters '1h,now/h' from 2020-09-01 10:00:00.000000000 +03:00 in: - period: 1h - shift: now/h + param: 1h:now/h timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: @@ -153,8 +137,7 @@ out: --- test case: Valid parameters '1h,now/d' from 2020-09-01 10:00:00.000000000 +03:00 in: - period: 1h - shift: now/d + param: 1h:now/d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: @@ -164,8 +147,7 @@ out: --- test case: Valid parameters '1h,now/h-1d' from 2020-09-01 10:00:00.000000000 +03:00 in: - period: 1h - shift: now/h-1d + param: 1h:now/h-1d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: @@ -175,8 +157,7 @@ out: --- test case: Valid parameters '1d,now/w-6d' from 2020-09-01 10:00:00.000000000 +03:00 in: - period: 1d - shift: now/w-6d + param: 1d:now/w-6d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: @@ -186,8 +167,7 @@ out: --- test case: Valid parameters '1d,now/M-1M+6d/w+1d' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1d - shift: now/M-1M+6d/w+1d + param: 1d:now/M-1M+6d/w+1d timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -197,8 +177,7 @@ out: --- test case: Valid parameters '1w,now/M' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1w - shift: now/M + param: 1w:now/M timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -208,8 +187,7 @@ out: --- test case: Valid parameters '1M,now/M' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/M + param: 1M:now/M timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -219,8 +197,7 @@ out: --- test case: Valid parameters '1M,now/M-1M' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/M-1M + param: 1M:now/M-1M timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -230,8 +207,7 @@ out: --- test case: Valid parameters '1M,now/M-2M' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/M-2M + param: 1M:now/M-2M timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -241,8 +217,7 @@ out: --- test case: Valid parameters '1d,now/y' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1d - shift: now/y + param: 1d:now/y timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -252,8 +227,7 @@ out: --- test case: Valid parameters '1h,now-1d' from 2020-09-01 10:00:00.000000000 +03:00 in: - period: 1h - shift: now-1d + param: 1h:now-1d timezone: :Europe/Riga time: 2020-09-01 10:00:00.000000000 +03:00 out: @@ -263,8 +237,7 @@ out: --- test case: Valid parameters '3h,now-1d/h' from 2020-09-01 10:30:00.000000000 +03:00 in: - period: 3h - shift: now-1d/h + param: 3h:now-1d/h timezone: :Europe/Riga time: 2020-09-01 10:30:00.000000000 +03:00 out: @@ -274,8 +247,7 @@ out: --- test case: Valid parameters '3h,now+1d-3d/w' from 2020-09-01 10:30:00.000000000 +03:00 in: - period: 3h - shift: now+1d-3d/w + param: 3h:now+1d-3d/w timezone: :Europe/Riga time: 2020-09-01 10:30:00.000000000 +03:00 out: @@ -285,8 +257,7 @@ out: --- test case: Invalid parameters '1M,now/h' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/h + param: 1M:now/h timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -294,8 +265,7 @@ out: --- test case: Invalid parameters '1M,now/d' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/d + param: 1M:now/d timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -303,8 +273,7 @@ out: --- test case: Invalid parameters '1M,now/w' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/w + param: 1M:now/w timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -312,8 +281,7 @@ out: --- test case: Invalid parameters '1M,now/M-1h' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/M-1h + param: 1M:now/M-1h timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -321,8 +289,7 @@ out: --- test case: Invalid parameters '1M,now/M-1d' from 2020-09-18 10:00:00.000000000 +03:00 in: - period: 1M - shift: now/M-1d + param: 1M:now/M-1d timezone: :Europe/Riga time: 2020-09-18 10:00:00.000000000 +03:00 out: @@ -330,8 +297,7 @@ out: --- test case: Valid period '1y' in: - period: 1y - shift: now/y + param: 1y:now/y timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -341,8 +307,7 @@ out: --- test case: Valid period '12M' in: - period: 12M - shift: now/y + param: 12M:now/y timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -352,8 +317,7 @@ out: --- test case: Valid period '366d' in: - period: 366d - shift: now/y + param: 366d:now/y timezone: :Europe/Riga time: 2021-09-01 00:00:00.000000000 +03:00 out: @@ -363,8 +327,7 @@ out: --- test case: Valid period '8784h' in: - period: 8784h - shift: now/y + param: 8784h:now/y timezone: :Europe/Riga time: 2021-09-01 00:00:00.000000000 +03:00 out: @@ -374,8 +337,7 @@ out: --- test case: Invalid period '2y' in: - period: 2y - shift: now/y + param: 2y:now/y timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -383,8 +345,7 @@ out: --- test case: Invalid period '13M' in: - period: 13M - shift: now/y + param: 13M:now/y timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -392,8 +353,7 @@ out: --- test case: Invalid period '367d' in: - period: 367d - shift: now/y + param: 367d:now/y timezone: :Europe/Riga time: 2020-09-01 00:00:00.000000000 +03:00 out: @@ -401,8 +361,7 @@ out: --- test case: Invalid period '8785h' in: - period: 8785h - shift: now/y + param: 8785h:now/y timezone: :Europe/Riga time: 2021-09-01 00:00:00.000000000 +03:00 out: @@ -410,8 +369,7 @@ out: --- test case: Invalid shift '26y' in: - period: 1h - shift: now/y-26y + param: 1h:now/y-26y timezone: :Europe/Riga time: 2021-09-01 00:00:00.000000000 +03:00 out: @@ -419,8 +377,7 @@ out: --- test case: Valid shift '25y' in: - period: 1h - shift: now/y-25y + param: 1h:now/y-25y timezone: :Europe/Riga time: 2021-09-01 00:00:00.000000000 +03:00 out: @@ -428,10 +385,9 @@ out: end: 1995-12-31 23:00:00.000000000 +02:00 return: SUCCEED --- -test case: Valid parameters '1h,now/M+6d/w+1h' from 2020-09-23 00:59:46.000000000 +03:00 +test case: Valid parameters '1h:now/M+6d/w+1h' from 2020-09-23 00:59:46.000000000 +03:00 in: - period: 1h - shift: now/M+6d/w+1h + param: 1h:now/M+6d/w+1h timezone: :Europe/Riga time: 2020-09-23 00:59:46.000000000 +03:00 out: diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index dc248420834..9cd8687be99 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -21,7 +21,7 @@ define('ZABBIX_VERSION', '5.4.0alpha1'); define('ZABBIX_API_VERSION', '5.4.0'); define('ZABBIX_EXPORT_VERSION', '5.4'); -define('ZABBIX_DB_VERSION', 5030026); +define('ZABBIX_DB_VERSION', 5030025); define('ZABBIX_COPYRIGHT_FROM', '2001'); define('ZABBIX_COPYRIGHT_TO', '2021'); |