mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
This is a translation of services/alerting/conditions. Main Changes: - Work with types in SSE (series/number) which are data frames (no more null.Float). - The query part from alerting/conditions is handled by SSE logic - Convey / simplejson removed. - Time range no longer part of "query" in the condition
421 lines
14 KiB
Go
421 lines
14 KiB
Go
package classic
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/expr/mathexp"
|
|
"github.com/stretchr/testify/require"
|
|
ptr "github.com/xorcare/pointer"
|
|
)
|
|
|
|
func TestReducer(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
reducer classicReducer
|
|
inputSeries mathexp.Series
|
|
expectedNumber mathexp.Number
|
|
}{
|
|
{
|
|
name: "sum",
|
|
reducer: classicReducer("sum"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(6)),
|
|
},
|
|
{
|
|
name: "min",
|
|
reducer: classicReducer("min"),
|
|
inputSeries: valBasedSeries(ptr.Float64(3), ptr.Float64(2), ptr.Float64(1)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(1)),
|
|
},
|
|
{
|
|
name: "min with NaNs only",
|
|
reducer: classicReducer("min"),
|
|
inputSeries: valBasedSeries(ptr.Float64(math.NaN()), ptr.Float64(math.NaN()), ptr.Float64(math.NaN())),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
{
|
|
name: "max",
|
|
reducer: classicReducer("max"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(3)),
|
|
},
|
|
{
|
|
name: "count",
|
|
reducer: classicReducer("count"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(3)),
|
|
},
|
|
{
|
|
name: "last",
|
|
reducer: classicReducer("last"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(3000)),
|
|
},
|
|
{
|
|
name: "median with odd amount of numbers",
|
|
reducer: classicReducer("median"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3000)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(2)),
|
|
},
|
|
{
|
|
name: "median with even amount of numbers",
|
|
reducer: classicReducer("median"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(4), ptr.Float64(3000)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(3)),
|
|
},
|
|
{
|
|
name: "median with one value",
|
|
reducer: classicReducer("median"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(1)),
|
|
},
|
|
{
|
|
name: "median should ignore null values",
|
|
reducer: classicReducer("median"),
|
|
inputSeries: valBasedSeries(nil, nil, nil, ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(2)),
|
|
},
|
|
{
|
|
name: "avg",
|
|
reducer: classicReducer("avg"),
|
|
inputSeries: valBasedSeries(ptr.Float64(1), ptr.Float64(2), ptr.Float64(3)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(2)),
|
|
},
|
|
{
|
|
name: "avg with only nulls",
|
|
reducer: classicReducer("avg"),
|
|
inputSeries: valBasedSeries(nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
{
|
|
name: "avg of number values and null values should ignore nulls",
|
|
reducer: classicReducer("avg"),
|
|
inputSeries: valBasedSeries(ptr.Float64(3), nil, nil, ptr.Float64(3)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(3)),
|
|
},
|
|
{
|
|
name: "count_non_null with mixed null/real values",
|
|
reducer: classicReducer("count_non_null"),
|
|
inputSeries: valBasedSeries(nil, nil, ptr.Float64(3), ptr.Float64(4)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(2)),
|
|
},
|
|
{
|
|
name: "count_non_null with no values",
|
|
reducer: classicReducer("count_non_null"),
|
|
inputSeries: valBasedSeries(nil, nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
num := tt.reducer.Reduce(tt.inputSeries)
|
|
require.Equal(t, tt.expectedNumber, num)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDiffReducer(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
inputSeries mathexp.Series
|
|
expectedNumber mathexp.Number
|
|
}{
|
|
{
|
|
name: "diff of one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "diff of one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "diff two positive points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(10)),
|
|
},
|
|
{
|
|
name: "diff two positive points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(20)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-10)),
|
|
},
|
|
{
|
|
name: "diff two negative points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-10)),
|
|
},
|
|
{
|
|
name: "diff two negative points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-10)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(20)),
|
|
},
|
|
{
|
|
name: "diff of one positive and one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-70)),
|
|
},
|
|
{
|
|
name: "diff of one negative and one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(70)),
|
|
},
|
|
{
|
|
name: "diff of three positive points",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40), ptr.Float64(50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(20)),
|
|
},
|
|
{
|
|
name: "diff of three negative points",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40), ptr.Float64(-50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-20)),
|
|
},
|
|
{
|
|
name: "diff with only nulls",
|
|
inputSeries: valBasedSeries(nil, nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
num := classicReducer("diff").Reduce(tt.inputSeries)
|
|
require.Equal(t, tt.expectedNumber, num)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDiffAbsReducer(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
inputSeries mathexp.Series
|
|
expectedNumber mathexp.Number
|
|
}{
|
|
{
|
|
name: "diff_abs of one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "diff_abs of one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "diff_abs two positive points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(10)),
|
|
},
|
|
{
|
|
name: "diff_abs two positive points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(20)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(10)),
|
|
},
|
|
{
|
|
name: "diff_abs two negative points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(10)),
|
|
},
|
|
{
|
|
name: "diff_abs two negative points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-10)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(20)),
|
|
},
|
|
{
|
|
name: "diff_abs of one positive and one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(70)),
|
|
},
|
|
{
|
|
name: "diff_abs of one negative and one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(70)),
|
|
},
|
|
{
|
|
name: "diff_abs of three positive points",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40), ptr.Float64(50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(20)),
|
|
},
|
|
{
|
|
name: "diff_abs of three negative points",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40), ptr.Float64(-50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(20)),
|
|
},
|
|
{
|
|
name: "diff_abs with only nulls",
|
|
inputSeries: valBasedSeries(nil, nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
num := classicReducer("diff_abs").Reduce(tt.inputSeries)
|
|
require.Equal(t, tt.expectedNumber, num)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPercentDiffReducer(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
inputSeries mathexp.Series
|
|
expectedNumber mathexp.Number
|
|
}{
|
|
{
|
|
name: "percent_diff of one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "percent_diff of one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "percent_diff two positive points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff two positive points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(20)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff two negative points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff two negative points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-10)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff of one positive and one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-233.33333333333334)),
|
|
},
|
|
{
|
|
name: "percent_diff of one negative and one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(233.33333333333334)),
|
|
},
|
|
{
|
|
name: "percent_diff of three positive points",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40), ptr.Float64(50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff of three negative points",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40), ptr.Float64(-50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(-66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff with only nulls",
|
|
inputSeries: valBasedSeries(nil, nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
num := classicReducer("percent_diff").Reduce(tt.inputSeries)
|
|
require.Equal(t, tt.expectedNumber, num)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPercentDiffAbsReducer(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
inputSeries mathexp.Series
|
|
expectedNumber mathexp.Number
|
|
}{
|
|
{
|
|
name: "percent_diff_abs of one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs of one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(0)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs two positive points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs two positive points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(20)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs two negative points [1]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(33.33333333333333)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs two negative points [2]",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-10)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs of one positive and one negative point",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(-40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(233.33333333333334)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs of one negative and one positive point",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(40)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(233.33333333333334)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs of three positive points",
|
|
inputSeries: valBasedSeries(ptr.Float64(30), ptr.Float64(40), ptr.Float64(50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs of three negative points",
|
|
inputSeries: valBasedSeries(ptr.Float64(-30), ptr.Float64(-40), ptr.Float64(-50)),
|
|
expectedNumber: valBasedNumber(ptr.Float64(66.66666666666666)),
|
|
},
|
|
{
|
|
name: "percent_diff_abs with only nulls",
|
|
inputSeries: valBasedSeries(nil, nil),
|
|
expectedNumber: valBasedNumber(nil),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
num := classicReducer("percent_diff_abs").Reduce(tt.inputSeries)
|
|
require.Equal(t, tt.expectedNumber, num)
|
|
})
|
|
}
|
|
}
|
|
|
|
func valBasedSeries(vals ...*float64) mathexp.Series {
|
|
newSeries := mathexp.NewSeries("", nil, 0, false, 1, true, len(vals))
|
|
for idx, f := range vals {
|
|
err := newSeries.SetPoint(idx, unixTimePointer(int64(idx)), f)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
return newSeries
|
|
}
|
|
|
|
func unixTimePointer(sec int64) *time.Time {
|
|
t := time.Unix(sec, 0)
|
|
return &t
|
|
}
|
|
|
|
func valBasedNumber(f *float64) mathexp.Number {
|
|
newNumber := mathexp.NewNumber("", nil)
|
|
newNumber.SetValue(f)
|
|
return newNumber
|
|
}
|